1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2012 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#define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIDSystem"
25//#define DEBUG_ASSERT_PRODUCTION_CODE 0
26
27
28#include <AssertMacros.h>
29#include "IOHIDKeys.h"
30
31#include "IOHIDEvent.h"
32#include <IOKit/system.h>
33#include <IOKit/assert.h>
34
35#include <libkern/c++/OSContainers.h>
36#include <libkern/c++/OSCollectionIterator.h>
37
38#include <kern/queue.h>
39
40#include <IOKit/IOTimerEventSource.h>
41#include <IOKit/IOCommandGate.h>
42#include <IOKit/IOMessage.h>
43#include <IOKit/IOWorkLoop.h>
44#include <IOKit/IOPlatformExpert.h>
45#include <IOKit/hidsystem/IOHIDevice.h>
46#include <IOKit/hidsystem/IOHIDParameter.h>
47#include <IOKit/usb/USB.h>
48#include <IOKit/pwr_mgt/RootDomain.h>
49#include <kern/clock.h>
50#include "IOHIDShared.h"
51#include "IOHIDSystem.h"
52#include "IOHIDEventService.h"
53#include "IOHIDPointing.h"
54#include "IOHIDKeyboard.h"
55#include "IOHIDConsumer.h"
56#include "IOHITablet.h"
57#include "IOHIDPointingDevice.h"
58#include "IOHIDKeyboardDevice.h"
59#include "IOHIDPrivate.h"
60#include "IOHIDPrivateKeys.h"
61#include "IOHIDEventServiceQueue.h"
62#include "IOLLEvent.h"
63
64#include "ev_private.h"
65#include "IOHIDUserClient.h"
66#include "AppleHIDUsageTables.h"
67#include "IOHIDKeyboard.h"
68#include "IOHIDFamilyTrace.h"
69#include "IOHIDWorkLoop.h"
70#include "IOHIDSystemCursorHelper.h"
71
72#include <sys/kdebug.h>
73#include <sys/proc.h>
74
75#ifdef __cplusplus
76    extern "C"
77    {
78        #include <UserNotification/KUNCUserNotifications.h>
79        void cons_cinput( char c);
80    }
81#endif
82
83extern "C" {
84    #include <sys/kauth.h>
85
86    #define CONFIG_MACF 1
87    #include <security/mac_framework.h>
88    #undef CONFIG_MACF
89};
90
91bool displayWranglerUp( OSObject *, void *, IOService * );
92
93#if 0
94#define PROFILE_TRACE(X)     IOHID_DEBUG(kIOHIDDebugCode_Profiling, X, __LINE__, 0, 0)
95#else
96#define PROFILE_TRACE(X)
97#endif
98
99static IOHIDSystem * evInstance = 0;
100MasterAudioFunctions *masterAudioFunctions = 0;
101
102#define xpr_ev_cursor(x, a, b, c, d, e)
103
104#ifndef kIOFBWaitCursorFramesKey
105#define kIOFBWaitCursorFramesKey    "IOFBWaitCursorFrames"
106#endif
107#ifndef kIOFBWaitCursorPeriodKey
108#define kIOFBWaitCursorPeriodKey    "IOFBWaitCursorPeriod"
109#endif
110
111#ifndef kIOUserClientCrossEndianKey
112#define kIOUserClientCrossEndianKey "IOUserClientCrossEndian"
113#endif
114
115#ifndef kIOUserClientCrossEndianCompatibleKey
116#define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible"
117#endif
118
119#ifndef abs
120#define abs(_a) ((_a >= 0) ? _a : -_a)
121#endif
122
123#define NORMAL_MODIFIER_MASK (NX_COMMANDMASK | NX_CONTROLMASK | NX_SHIFTMASK | NX_ALTERNATEMASK)
124
125#define EV_MAX_SCREENS 32
126
127#define IDLE_HID_ACTIVITY_NSECS ((uint64_t)(5*60*NSEC_PER_SEC))
128
129static inline unsigned AbsoluteTimeToTick( AbsoluteTime * ts )
130{
131    UInt64  nano;
132    absolutetime_to_nanoseconds(*ts, &nano);
133    return( nano >> 24 );
134}
135
136static inline void TickToAbsoluteTime( unsigned tick, AbsoluteTime * ts )
137{
138    UInt64  nano = ((UInt64) tick) << 24;
139    nanoseconds_to_absolutetime(nano, ts);
140}
141
142static UInt8 ScalePressure(unsigned pressure)
143{
144    return ((pressure * (unsigned long long)EV_MAXPRESSURE) / (unsigned)(65535LL));
145}
146
147#define EV_NS_TO_TICK(ns)   AbsoluteTimeToTick(ns)
148#define EV_TICK_TO_NS(tick,ns)  TickToAbsoluteTime(tick,ns)
149
150/* COMMAND GATE COMPATIBILITY TYPE DEFS */
151typedef struct _IOHIDCmdGateActionArgs {
152    void*   arg0;
153    void*   arg1;
154    void*   arg2;
155    void*   arg3;
156    void*   arg4;
157    void*   arg5;
158    void*   arg6;
159    void*   arg7;
160    void*   arg8;
161    void*   arg9;
162    void*   arg10;
163    void*   arg11;
164} IOHIDCmdGateActionArgs;
165/* END COMMAND GATE COMPATIBILITY TYPE DEFS */
166
167/* HID SYSTEM EVENT LOCK OUT SUPPORT */
168
169static bool         gKeySwitchLocked = false;
170static bool             gUseKeyswitch = true;
171static IONotifier *     gSwitchNotification = 0;
172
173// IONotificationHandler
174static bool keySwitchNotificationHandler(void *target __unused, void *refCon __unused, IOService *service, IONotifier * /* ignored */)
175{
176
177    gKeySwitchLocked = (service->getProperty("Keyswitch") == kOSBooleanTrue);
178
179    return true;
180}
181
182/* END HID SYSTEM EVENT LOCK OUT SUPPORT */
183
184// RY: Consume any keyboard events that come in before the
185// deadline after the system wakes up or if the keySwitch is locked
186#define kHIDConsumeCauseNone    0x00
187#define kHIDConsumeCauseKeyLock 0x01
188#define kHIDConsumeCauseDeadline 0x02
189
190static inline UInt32 ShouldConsumeHIDEvent(AbsoluteTime ts, AbsoluteTime deadline, bool checkKeySwitch = true )
191{
192    if (checkKeySwitch && gKeySwitchLocked && gUseKeyswitch)
193        return kHIDConsumeCauseKeyLock;
194
195    if ( AbsoluteTime_to_scalar(&ts) == 0 )
196        clock_get_uptime(&ts);
197
198    if (CMP_ABSOLUTETIME(&ts, &deadline) <= 0)
199    {
200         return kHIDConsumeCauseDeadline;
201    }
202
203    return kHIDConsumeCauseNone;
204}
205
206#define WAKE_DISPLAY_ON_MOVEMENT (NX_WAKEMASK & MOVEDEVENTMASK)
207
208#define DISPLAY_IS_ENABLED (displayState & IOPMDeviceUsable)
209
210#define TICKLE_DISPLAY(event) \
211{ \
212    if (!evStateChanging && displayManager) { \
213        IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, event, __LINE__, 0, 0); \
214        if (!DISPLAY_IS_ENABLED) kprintf("IOHIDSystem tickle when screen off for event %d at line %d\n", (int)event, __LINE__); \
215        displayManager->activityTickle(IOHID_DEBUG_CODE(event)); \
216    } \
217    updateHidActivity(); \
218}
219
220#define CONVERT_EV_TO_HW_BUTTONS(ev_buttons,hw_buttons)                         \
221        hw_buttons = ev_buttons & ~7; /* Keep everything but bottom 3 bits. */  \
222        hw_buttons |= (ev_buttons & 3) << 1;  /* Map bits 01 to 12 */           \
223        hw_buttons |= (ev_buttons & 4) >> 2;  /* Map bit 2 back to bit 0 */
224
225#define CONVERT_EV_TO_HW_DELTA(ev_buttons,hw_delta)                             \
226        hw_delta = ev_buttons & ~7;                                             \
227        hw_delta |= (ev_buttons & 3) << 1; /* Map bits 01 to 12 */              \
228        hw_delta |= (ev_buttons & 4) >> 2; /* Map bit 2 back to bit 0 */
229
230#define CONVERT_HW_TO_WV_BUTTONS(hw_buttons,ev_buttons)                         \
231        ev_buttons = hw_buttons & ~7; /* Keep everything but bottom 3 bits. */  \
232        ev_buttons |= (hw_buttons & 6) >> 1;  /* Map bits 12 to 01 */           \
233        ev_buttons |= (hw_buttons & 1) << 2;  /* Map bit 0 to bit 2 */
234
235
236
237enum {
238    // Options for IOHIDPostEvent()
239    kIOHIDSetGlobalEventFlags       = 0x00000001,
240    kIOHIDSetCursorPosition         = 0x00000002,
241    kIOHIDSetRelativeCursorPosition = 0x00000004,
242    kIOHIDPostHIDManagerEvent       = 0x00000008
243};
244
245#define kIOHIDPowerOnThresholdNS            (500ULL * kMillisecondScale)    // 1/2 second
246#define kIOHIDRelativeTickleThresholdNS     (50ULL * kMillisecondScale)     // 1/20 second
247#define kIOHIDRelativeTickleThresholdPixel  3
248#define kIOHIDDispaySleepAbortThresholdNS   (5ULL * kSecondScale)           // 5 seconds
249#define kIOHIDChattyMouseSuppressionDelayNS kSecondScale                    // 1 second
250
251static AbsoluteTime gIOHIDPowerOnThresoldAbsoluteTime;
252static AbsoluteTime gIOHIDRelativeTickleThresholdAbsoluteTime;
253// gIOHIDDisplaySleepAbortThresholdAbsoluteTime  - Time before which display sleep
254// can be aborted by a mouse/scroll motion
255static AbsoluteTime gIOHIDDisplaySleepAbortThresholdAbsoluteTime;
256static AbsoluteTime gIOHIDZeroAbsoluteTime;
257
258typedef struct _stackShotMgs {
259    mach_msg_header_t   header;
260    UInt32              flavor;
261} _stackShotMessage;
262
263//************************************************************
264// Cached Mouse Event Info Support
265//************************************************************
266enum {
267    kCachedMousePointingTabletEventDispFlag = 0x01,
268    kCachedMousePointingTabletEventPendFlag = 0x02,
269    kCachedMousePointingEventDispFlag       = 0x04,
270    kCachedMouseTabletEventDispFlag         = 0x08
271};
272
273typedef struct _CachedMouseEventStruct {
274    OSObject *                  service;
275    UInt64                      eventDeadline;
276    UInt64                      reportInterval_ns;
277    SInt32                      lastButtons;
278    SInt32                      accumX;
279    SInt32                      accumY;
280    bool                        proximity;
281    UInt32                      state;
282    UInt8                       subType;
283    NXEventData                 tabletData;
284    NXEventData                 proximityData;
285    UInt16                      pointerFractionX;
286    UInt16                      pointerFractionY;
287    UInt8                       lastPressure;
288} CachedMouseEventStruct;
289
290//************************************************************
291static void CalculateEventCountsForService(CachedMouseEventStruct *mouseStruct)
292{
293    if ( mouseStruct ) {
294        mouseStruct->reportInterval_ns = 8000000; // default to 8ms
295        if ( mouseStruct->service ) {
296            IORegistryEntry *senderEntry = OSDynamicCast(IORegistryEntry, mouseStruct->service);
297            if (senderEntry) {
298                OSNumber *reportInterval_us = (OSNumber*)senderEntry->copyProperty(kIOHIDReportIntervalKey, gIOServicePlane, kIORegistryIterateRecursively| kIORegistryIterateParents);
299                if (OSDynamicCast(OSNumber, reportInterval_us)) {
300                    mouseStruct->reportInterval_ns = reportInterval_us->unsigned64BitValue() * 1000;
301                }
302                else {
303                    IOLog("No interval found for %s. Using %lld\n", senderEntry->getLocation(), mouseStruct->reportInterval_ns);
304                }
305                OSSafeReleaseNULL(reportInterval_us);
306            }
307        }
308    }
309}
310
311//************************************************************
312static void CalculateEventCountsForAllServices(OSArray *events)
313{
314    if ( events )
315    {
316        int count = events->getCount();
317        int i;
318
319        for ( i=0; i<count; i++ )
320        {
321            OSData *data;
322            CachedMouseEventStruct *mouseEvent;
323            if ( (data = (OSData *)events->getObject(i) ) &&
324                (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) )
325            {
326                CalculateEventCountsForService(mouseEvent);
327            }
328        }
329    }
330}
331
332//************************************************************
333static SInt32 GetCachedMouseButtonStates(OSArray *events)
334{
335    CachedMouseEventStruct *    mouseEvent  = 0;
336    OSData *                    data        = 0;
337    SInt32                      buttonState = 0;
338    UInt32                      count       = 0;
339    UInt32                      i           = 0;
340
341    if ( events )
342    {
343        count = events->getCount();
344
345        for ( i=0; i<count; i++ )
346        {
347            if ( (data = (OSData *)events->getObject(i)) &&
348                (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()))
349            {
350                buttonState |= mouseEvent->lastButtons;
351            }
352        }
353    }
354
355    return buttonState;
356}
357
358//************************************************************
359static void ClearCachedMouseButtonStates(OSArray *events)
360{
361    CachedMouseEventStruct *    mouseEvent  = 0;
362    OSData *                    data        = 0;
363    UInt32                      count       = 0;
364    UInt32                      i           = 0;
365
366    if ( events )
367    {
368        count = events->getCount();
369
370        for ( i=0; i<count; i++ )
371        {
372            if ( (data = (OSData *)events->getObject(i)) &&
373                 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()))
374            {
375                mouseEvent->lastButtons = 0;
376                CalculateEventCountsForService(mouseEvent);
377            }
378        }
379    }
380}
381
382//************************************************************
383static CachedMouseEventStruct * GetCachedMouseEventForService(OSArray *events, OSObject *service, UInt32 * index = 0)
384{
385    CachedMouseEventStruct *    mouseEvent  = 0;
386    OSData *                    data        = 0;
387    UInt32                      count       = 0;
388    UInt32                      i           = 0;
389
390    if ( events )
391    {
392        count = events->getCount();
393
394        for ( i=0; i<count; i++ )
395        {
396            if ( (data = (OSData *)events->getObject(i)) &&
397                 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) &&
398                 (mouseEvent->service == service) )
399            {
400                if ( index ) *index = i;
401                return mouseEvent;
402            }
403        }
404    }
405
406    return NULL;
407}
408
409//************************************************************
410static void AppendNewCachedMouseEventForService(OSArray *events, OSObject *service)
411{
412    CachedMouseEventStruct  temp;
413    OSData *                data;
414
415    bzero(&temp, sizeof(CachedMouseEventStruct));
416    temp.service = service;
417
418    data = OSData::withBytes(&temp, sizeof(CachedMouseEventStruct));
419    events->setObject(data);
420    data->release();
421    CalculateEventCountsForAllServices(events);
422}
423
424//************************************************************
425static void RemoveCachedMouseEventForService(OSArray *events, OSObject *service)
426{
427    UInt32  index;
428
429    if ( events && GetCachedMouseEventForService(events, service, &index) )
430    {
431        events->removeObject(index);
432    }
433    CalculateEventCountsForAllServices(events);
434}
435
436//************************************************************
437// NX System Info Support
438//************************************************************
439#define kNXSystemInfoKey "NXSystemInfo"
440
441static void AppendNewNXSystemInfoForService(OSArray *systemInfo, IOService *service)
442{
443    OSDictionary *  deviceInfo  = NULL;
444    OSNumber *      deviceID    = NULL;
445    IOHIDevice *    hiDevice    = NULL;
446    OSObject *      object      = NULL;
447
448    if ( !systemInfo || !(hiDevice = OSDynamicCast(IOHIDevice, service)))
449        return;
450
451    deviceInfo = OSDictionary::withCapacity(4);
452
453    if ( !deviceInfo )
454        return;
455
456    deviceID = OSNumber::withNumber((uintptr_t)hiDevice, 64);
457    if (deviceID)
458    {
459        deviceInfo->setObject("serviceID", deviceID);
460        deviceID->release();
461    }
462
463    object = hiDevice->copyProperty(kIOHIDKindKey);
464    if ( object )
465    {
466        deviceInfo->setObject(kIOHIDKindKey, object);
467        object->release();
468    }
469
470    object = hiDevice->copyProperty(kIOHIDInterfaceIDKey);
471    if ( object )
472    {
473        deviceInfo->setObject(kIOHIDInterfaceIDKey, object);
474        object->release();
475    }
476
477    object = hiDevice->copyProperty(kIOHIDSubinterfaceIDKey);
478    if ( object )
479    {
480        deviceInfo->setObject(kIOHIDSubinterfaceIDKey, object);
481        object->release();
482    }
483
484    if ( hiDevice->metaCast("AppleADBKeyboard") || (hiDevice->getProvider() && hiDevice->getProvider()->metaCast("AppleEmbeddedKeyboard")) )
485        deviceInfo->setObject("built-in", kOSBooleanTrue);
486
487    // RY: Hack for rdar://4365935 Turning on NumLock causes Keyboard
488    // Viewer to display the external keyboard
489    // Because keyboardType information is not passed in special key
490    // events, CG infers that this event comes from the default keyboard,
491    // or first keyboard in NXSystemInfo. Unforunately, in some cases a
492    // USB external keyboard will enumerate before a USB internal keyboard.
493    // If this is encountered, we should alway insert the internal keyboard
494    // at the beginning of the list.  This will cause CG to guess correctly.
495    // RY: Extension for rdar://4418444 Keyboard Viewer defaults to wrong
496    // keyboard layout when launched.
497    // We should also insert keyboards to the front of the list, prefering
498    // Apple, if the front does not already contain a built-in keyboard.
499    OSDictionary * tempSystemInfo;
500    OSNumber * number;
501
502    // If a keyboard
503    if ( ((hiDevice->hidKind() == kHIKeyboardDevice) && (hiDevice->deviceType() != 0))&&
504            // And keyboard is built-in
505            ( (deviceInfo->getObject("built-in") == kOSBooleanTrue) ||
506            // Or, first item in the list is not a keyboard
507            !((tempSystemInfo = OSDynamicCast(OSDictionary, systemInfo->getObject(0))) && (number = OSDynamicCast(OSNumber,tempSystemInfo->getObject(kIOHIDKindKey))) && (number->unsigned32BitValue() == kHIKeyboardDevice)) ||
508            // Or, if the keyboard is Apple and the first item in the list is not built-in
509            // vtn3: potentially unsafe, but a pain to fix. leave it for now.
510            ((number = OSDynamicCast(OSNumber, hiDevice->getProperty(kIOHIDVendorIDKey))) && (number->unsigned32BitValue() == kIOUSBVendorIDAppleComputer) && (tempSystemInfo->getObject("built-in") != kOSBooleanTrue)) ) )
511    {
512        systemInfo->setObject(0, deviceInfo);
513    }
514    else
515    {
516        systemInfo->setObject(deviceInfo);
517    }
518
519    deviceInfo->release();
520}
521
522static void RemoveNXSystemInfoForService(OSArray *systemInfo, IOService *service)
523{
524    OSDictionary *  deviceInfo  = NULL;
525    OSNumber *      serviceID   = NULL;
526    UInt32          i, count;
527
528    if ( !systemInfo || !OSDynamicCast(IOHIDevice, service))
529        return;
530
531    count = systemInfo->getCount();
532
533    for ( i=0; i<count; i++ )
534    {
535        if ( (deviceInfo = (OSDictionary *)systemInfo->getObject(i)) &&
536             (serviceID = (OSNumber *)deviceInfo->getObject("serviceID")) &&
537             (serviceID->unsigned64BitValue() == (uintptr_t)service) )
538        {
539            systemInfo->removeObject(i);
540            break;
541        }
542    }
543}
544
545//************************************************************
546// keyboardEventQueue support
547//************************************************************
548static queue_head_t     gKeyboardEQ;
549static IOLock *         gKeyboardEQLock = 0;
550
551typedef IOReturn (*KeyboardEQAction)(IOHIDSystem * self, void *args);
552
553typedef struct _KeyboardEQElement {
554    queue_chain_t   link;
555
556    KeyboardEQAction    action;
557    OSObject *          sender;
558    AbsoluteTime        ts;
559
560    union {
561        struct {
562            unsigned        eventType;
563            unsigned        flags;
564            unsigned        key;
565            unsigned        charCode;
566            unsigned        charSet;
567            unsigned        origCharCode;
568            unsigned        origCharSet;
569            unsigned        keyboardType;
570            bool            repeat;
571        } keyboard;
572        struct {
573            unsigned        eventType;
574            unsigned        flags;
575            unsigned        key;
576            unsigned        flavor;
577            UInt64          guid;
578            bool            repeat;
579        } keyboardSpecial;
580        struct {
581            unsigned        flags;
582        } flagsChanged;
583    } event;
584} KeyboardEQElement;
585
586#define KEYBOARD_EQ_LOCK    if (gKeyboardEQLock) IOLockLock(gKeyboardEQLock);
587#define KEYBOARD_EQ_UNLOCK  if (gKeyboardEQLock) IOLockUnlock(gKeyboardEQLock);
588
589
590static UInt8 stickyKeysState = false;
591
592static void notifyHIDevices(IOService *service, OSArray *hiDevices, UInt32 type)
593{
594    IOHIKeyboard    *keyboard;
595
596    if(!stickyKeysState || !hiDevices)
597        return;
598
599    switch ( type )
600    {
601        case kIOHIDSystem508MouseClickMessage:
602        case kIOHIDSystem508SpecialKeyDownMessage:
603            for(unsigned index=0; index<hiDevices->getCount(); index++)
604            {
605                keyboard = OSDynamicCast(IOHIKeyboard, hiDevices->getObject(index));
606                if (keyboard)
607                    keyboard->IOHIKeyboard::message(type, service);
608            }
609            break;
610    }
611}
612
613/* This function exists because IOHIDSystem uses OSArrays of OSNumbers. Since
614 * OSArray::containsObject() compares by pointer equality instead of
615 * OSObject::isEqualTo().  OSNumbers cannot be found by value with
616 * containsObject(), so we must use this instead.
617 */
618#define kObjectNotFound ((unsigned int) -1)
619static unsigned int
620getArrayIndexForObject(OSArray *array, OSObject* object)
621{
622    OSObject *tmp;
623    u_int i;
624
625    for (i = 0; i < array->getCount(); ++i) {
626        tmp = array->getObject(i);
627        if (tmp->isEqualTo(object)) {
628            return i;
629        }
630    }
631
632    return kObjectNotFound;
633}
634
635static void
636hidActivityThread_cb(thread_call_param_t us, thread_call_param_t )
637{
638    ((IOHIDSystem *)us)->hidActivityChecker();
639}
640
641typedef struct {
642    IOCommandGate::Action   handler;
643    IOService               *newService;
644}
645IOHIDSystem_notificationData;
646
647#define super IOService
648OSDefineMetaClassAndStructors(IOHIDSystem, IOService);
649
650struct IOHIDSystem::ExpansionData
651{
652    // The goal of the cursorHelper is to isolate all of the cursor
653    // calculations and updates into one class.
654    IOHIDSystemCursorHelper cursorHelper;
655    UInt32                  delayedScrollMomentum;
656    UInt8                   scDirection;
657    UInt8                   scIgnoreMomentum;
658    UInt8                   scMouseCanReset;
659    UInt8                   scIncrementedThisPhrase;
660    UInt16                  scCount;
661    UInt16                  scCountMax;
662    IOFixed64               scAccelerationFactor;
663    UInt64                  scMinDeltaSqToStart;
664    UInt64                  scMinDeltaSqToSustain;
665    UInt64                  scLastScrollEndTime;
666    UInt64                  scLastScrollSustainTime;
667    UInt64                  scMaxTimeDeltaBetween;
668    UInt64                  scMaxTimeDeltaToSustain;
669    IOFixedPoint64          scLastScrollLocation;
670    OSDictionary            *devicePhaseState;
671
672    UInt64                  periodicEventLast;
673    UInt64                  periodicEventNext;
674    UInt64                  cursorEventLast;
675    UInt64                  cursorMoveLast;
676    UInt64                  cursorMoveDelta;
677    UInt64                  cursorWaitLast;
678    UInt64                  cursorWaitDelta;
679
680    IONotifier *            displayWranglerMatching;
681
682    bool                    hidActivityIdle; // Is HID activity idle for more than IDLE_HID_ACTIVITY_NSECS ?
683    AbsoluteTime            lastTickleTime;
684    thread_call_t           hidActivityThread;
685
686    // async delayed notifications
687    IOLock                  *delayedNotificationLock;
688    OSArray                 *delayedNotificationArray;
689    IOTimerEventSource      *delayedNotificationSource;
690};
691
692#define _cursorHelper               (_privateData->cursorHelper)
693#define _devicePhaseState           (_privateData->devicePhaseState)
694#define _delayedScrollMomentum      (_privateData->delayedScrollMomentum)
695#define _scCount                    (_privateData->scCount)
696#define _scCountMax                 (_privateData->scCountMax)
697#define _scDirection                (_privateData->scDirection)
698#define _scIgnoreMomentum           (_privateData->scIgnoreMomentum)
699#define _scIncrementedThisPhrase    (_privateData->scIncrementedThisPhrase)
700#define _scMouseCanReset            (_privateData->scMouseCanReset)
701#define _scMinDeltaSqToStart        (_privateData->scMinDeltaSqToStart)
702#define _scMinDeltaSqToSustain      (_privateData->scMinDeltaSqToSustain)
703#define _scLastScrollEndTime        (_privateData->scLastScrollEndTime)
704#define _scLastScrollSustainTime    (_privateData->scLastScrollSustainTime)
705#define _scMaxTimeDeltaBetween      (_privateData->scMaxTimeDeltaBetween)
706#define _scMaxTimeDeltaToSustain    (_privateData->scMaxTimeDeltaToSustain)
707#define _scLastScrollLocation       (_privateData->scLastScrollLocation)
708#define _scAccelerationFactor       (_privateData->scAccelerationFactor)
709
710#define _periodicEventLast          (_privateData->periodicEventLast)
711#define _periodicEventNext          (_privateData->periodicEventNext)
712#define _cursorEventLast            (_privateData->cursorEventLast)
713#define _cursorMoveLast             (_privateData->cursorMoveLast)
714#define _cursorMoveDelta            (_privateData->cursorMoveDelta)
715#define _cursorWaitLast             (_privateData->cursorWaitLast)
716#define _cursorWaitDelta            (_privateData->cursorWaitDelta)
717
718#define _displayWranglerMatching    (_privateData->displayWranglerMatching)
719
720#define _hidActivityIdle            (_privateData->hidActivityIdle)
721#define _lastTickleTime             (_privateData->lastTickleTime)
722#define _hidActivityThread          (_privateData->hidActivityThread)
723
724#define _delayedNotificationLock    (_privateData->delayedNotificationLock)
725#define _delayedNotificationArray   (_privateData->delayedNotificationArray)
726#define _delayedNotificationSource  (_privateData->delayedNotificationSource)
727
728enum {
729    kScrollDirectionInvalid = 0,
730    kScrollDirectionXPositive,
731    kScrollDirectionXNegative,
732    kScrollDirectionYPositive,
733    kScrollDirectionYNegative,
734    kScrollDirectionZPositive,
735    kScrollDirectionZNegative,
736};
737
738#define _cursorLog(ts)      do { \
739                                if (evg != 0) \
740                                    if (evg->logCursorUpdates) { \
741                                        _cursorHelper.logPosition(__func__, ts); \
742                                    } \
743                            } \
744                            while(false)
745
746#define _cursorLogTimed()   do { \
747                                if (evg != 0) \
748                                    if (evg->logCursorUpdates) { \
749                                        AbsoluteTime ts; \
750                                        clock_get_uptime(&ts); \
751                                        _cursorHelper.logPosition(__func__, AbsoluteTime_to_scalar(&ts)); \
752                                    } \
753                            } \
754                            while(false)
755
756/* Return the current instance of the EventDriver, or 0 if none. */
757IOHIDSystem * IOHIDSystem::instance()
758{
759  return evInstance;
760}
761
762#define kDefaultMinimumDelta    0x1ffffffffULL
763
764bool IOHIDSystem::init(OSDictionary * properties)
765{
766    if (!super::init(properties))
767        return false;
768
769    _privateData = (ExpansionData*)IOMalloc(sizeof(ExpansionData));
770    if (!_privateData)
771        return false;
772    bzero(_privateData, sizeof(ExpansionData));
773    _periodicEventNext = UINT64_MAX;
774
775    if (!_cursorHelper.init())
776        return false;
777    _cursorLogTimed();
778
779    // hard defaults. these exist just to keep the state machine sane.
780    _scMinDeltaSqToStart = _scMinDeltaSqToSustain = kDefaultMinimumDelta;
781    _scAccelerationFactor.fromIntFloor(5);
782    _scCountMax = 2000;
783
784    /*
785     * Initialize minimal state.
786     */
787    evScreen          = NULL;
788    periodicES        = 0;
789    eventConsumerES   = 0;
790    keyboardEQES      = 0;
791    cmdGate           = 0;
792    workLoop          = 0;
793    cachedEventFlags  = 0;
794    displayState = IOPMDeviceUsable;
795    AbsoluteTime_to_scalar(&lastEventTime) = 0;
796    AbsoluteTime_to_scalar(&lastUndimEvent) = 0;
797    AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0;
798    AbsoluteTime_to_scalar(&displayStateChangeDeadline) = 0;
799    AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0;
800    AbsoluteTime_to_scalar(&gIOHIDZeroAbsoluteTime) = 0;
801    displaySleepDrivenByPM = false;
802
803
804    ioHIDevices      = OSArray::withCapacity(2);
805    cachedButtonStates = OSArray::withCapacity(3);
806    touchEventPosters = OSSet::withCapacity(2);
807    consumedKeys = OSArray::withCapacity(5);
808
809    // RY: Populate cachedButtonStates key=0 with a button State
810    // This will cover all pointing devices that don't support
811    // the new private methods.
812    AppendNewCachedMouseEventForService(cachedButtonStates, 0);
813
814    nanoseconds_to_absolutetime(kIOHIDPowerOnThresholdNS, &gIOHIDPowerOnThresoldAbsoluteTime);
815    nanoseconds_to_absolutetime(kIOHIDRelativeTickleThresholdNS, &gIOHIDRelativeTickleThresholdAbsoluteTime);
816    nanoseconds_to_absolutetime(kIOHIDDispaySleepAbortThresholdNS, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime);
817
818    queue_init(&gKeyboardEQ);
819    gKeyboardEQLock = IOLockAlloc();
820    return true;
821}
822
823IOHIDSystem * IOHIDSystem::probe(IOService *    provider,
824                 SInt32 *   score)
825{
826  if (!super::probe(provider,score))  return 0;
827
828  return this;
829}
830
831/*
832 * Perform reusable initialization actions here.
833 */
834IOWorkLoop * IOHIDSystem::getWorkLoop() const
835{
836    return workLoop;
837}
838
839bool IOHIDSystem::start(IOService * provider)
840{
841    bool            iWasStarted = false;
842    OSObject        *obj = NULL;
843    OSNumber        *number = NULL;
844    OSDictionary    *matchingDevice = serviceMatching("IOHIDevice");
845    OSDictionary    *matchingService = serviceMatching("IOHIDEventService");
846    OSDictionary    *matchingWrangler = serviceMatching("IODisplayWrangler");
847    OSDictionary    *matchingKeyswitch = serviceMatching("AppleKeyswitch");
848    IOServiceMatchingNotificationHandler iohidNotificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &IOHIDSystem::genericNotificationHandler);
849
850    require(super::start(provider), exit_early);
851
852    _setScrollCountParameters();
853
854    evInstance = this;
855
856    /* A few details to be set up... */
857    _cursorHelper.desktopLocation().fromIntFloor(INIT_CURSOR_X, INIT_CURSOR_Y);
858    _cursorHelper.desktopLocationDelta().fromIntFloor(0, 0);
859    _cursorHelper.updateScreenLocation(NULL, NULL);
860    _cursorLogTimed();
861    _delayedNotificationLock = IOLockAlloc();
862    _delayedNotificationArray = OSArray::withCapacity(2);
863
864    evScreenSize = sizeof(EvScreen) * EV_MAX_SCREENS;
865    evScreen = (void *) IOMalloc(evScreenSize);
866    bzero(evScreen, evScreenSize);
867    savedParameters = OSDictionary::withCapacity(4);
868
869    require(evScreen && savedParameters && _delayedNotificationLock && _delayedNotificationArray, exit_early);
870
871    bzero(evScreen, evScreenSize);
872    firstWaitCursorFrame = EV_WAITCURSOR;
873    maxWaitCursorFrame   = EV_MAXCURSOR;
874    createParameters();
875
876    // Allocated and publish the systemInfo array
877    systemInfo = OSArray::withCapacity(4);
878    if (systemInfo) {
879        setProperty(kNXSystemInfoKey, systemInfo);
880    }
881
882    // Let's go ahead and cache our registry name.
883    // This was added to remove a call to getName while
884    // we are disabling preemption
885    registryName = getName();
886
887    obj = copyProperty(kIOHIDPowerOnDelayNSKey, gIOServicePlane);
888    if (obj != NULL) {
889        number = OSDynamicCast(OSNumber, obj);
890        if (number != NULL) {
891            UInt64 value = number->unsigned64BitValue();
892            if (value < kMillisecondScale) {
893                // logging not yet available
894            }
895            else if (value > (10ULL * kSecondScale)) {
896                // logging not yet available
897            }
898            else {
899                setProperty(kIOHIDPowerOnDelayNSKey, number);
900                gIOHIDPowerOnThresoldAbsoluteTime = value;
901            }
902        }
903        obj->release();
904    }
905
906    /*
907     * Start up the work loop
908     */
909    workLoop = IOHIDWorkLoop::workLoop();
910    cmdGate = IOCommandGate::commandGate(this);
911    periodicES = IOTimerEventSource::timerEventSource(this, (IOTimerEventSource::Action) &_periodicEvents );
912    eventConsumerES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doKickEventConsumer);
913    keyboardEQES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doProcessKeyboardEQ);
914    _delayedNotificationSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDSystem::doProcessNotifications));
915
916    require(workLoop && cmdGate && periodicES && eventConsumerES && keyboardEQES && _delayedNotificationSource, exit_early);
917
918    require_noerr(workLoop->addEventSource(cmdGate), exit_early);
919    require_noerr(workLoop->addEventSource(periodicES), exit_early);
920    require_noerr(workLoop->addEventSource(eventConsumerES), exit_early);
921    require_noerr(workLoop->addEventSource(keyboardEQES), exit_early);
922    require_noerr(workLoop->addEventSource(_delayedNotificationSource), exit_early);
923
924    publishNotify = addMatchingNotification(gIOPublishNotification,
925                                            matchingDevice,
926                                            iohidNotificationHandler,
927                                            this,
928                                            (void *)&IOHIDSystem::handlePublishNotification );
929    require(publishNotify, exit_early);
930
931    eventPublishNotify = addMatchingNotification(gIOPublishNotification,
932                                                 matchingService,
933                                                 iohidNotificationHandler,
934                                                 this,
935                                                 (void *)&IOHIDSystem::handlePublishNotification );
936    require(eventPublishNotify, exit_early);
937
938    terminateNotify = addMatchingNotification(gIOTerminatedNotification,
939                                              matchingDevice,
940                                              iohidNotificationHandler,
941                                              this,
942                                              (void *)&IOHIDSystem::handleTerminateNotification );
943    require(terminateNotify, exit_early);
944
945    eventTerminateNotify = addMatchingNotification(gIOTerminatedNotification,
946                                                   matchingService,
947                                                   iohidNotificationHandler,
948                                                   this,
949                                                   (void *)&IOHIDSystem::handleTerminateNotification );
950    require(eventTerminateNotify, exit_early);
951
952    // RY: Listen to the root domain
953    rootDomain = (IOService *)getPMRootDomain();
954
955    if (rootDomain)
956        rootDomain->registerInterestedDriver(this);
957
958    registerPrioritySleepWakeInterest(powerStateHandler, this, 0);
959
960    _displayWranglerMatching = addMatchingNotification(gIOPublishNotification,
961                                                       matchingWrangler,
962                                                       iohidNotificationHandler,
963                                                       this,
964                                                       (void *)&IOHIDSystem::handlePublishNotification);
965    require(_displayWranglerMatching, exit_early);
966
967    // Get notified everytime AppleKeyswitch registers (each time keyswitch changes)
968    gSwitchNotification = addMatchingNotification(gIOPublishNotification,
969                                                  matchingKeyswitch,
970                                                  keySwitchNotificationHandler,
971                                                  this,
972                                                  0);
973    require(gSwitchNotification, exit_early);
974
975    /*
976     * IOHIDSystem serves both as a service and a nub (we lead a double
977     * life).  Register ourselves as a nub to kick off matching.
978     */
979
980#if !TARGET_OS_EMBEDDED
981    _hidActivityThread = thread_call_allocate(hidActivityThread_cb, (thread_call_param_t)this);
982    _hidActivityIdle = true;
983    require(_hidActivityThread, exit_early);
984#endif
985
986    registerService();
987    iWasStarted = true;
988
989exit_early:
990    matchingDevice->release();
991    matchingService->release();
992    matchingWrangler->release();
993    matchingKeyswitch->release();
994
995    if (!iWasStarted)
996        evInstance = 0;
997
998    return iWasStarted;
999}
1000
1001void IOHIDSystem::setDisplaySleepDrivenByPM(bool val)
1002{
1003  displaySleepDrivenByPM = val;
1004}
1005
1006IOReturn IOHIDSystem::powerStateHandler( void *target, void *refCon __unused,
1007                        UInt32 messageType, IOService *service __unused, void *messageArgs, vm_size_t argSize __unused)
1008{
1009
1010   IOPMSystemCapabilityChangeParameters * params;
1011   IOHIDSystem*  myThis = OSDynamicCast( IOHIDSystem, (OSObject*)target );
1012
1013
1014   if ( messageType != kIOMessageSystemCapabilityChange ) {
1015      // We are not interested in anything other than cap change.
1016      return kIOReturnSuccess;
1017   }
1018   params = (IOPMSystemCapabilityChangeParameters *) messageArgs;
1019
1020   if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
1021       (params->fromCapabilities & kIOPMSystemCapabilityGraphics) &&
1022       (params->toCapabilities & kIOPMSystemCapabilityGraphics) == 0) {
1023
1024      /*
1025       * This display sleep driven by IOPMrootDomain. Don't let HID activity
1026       * tickle display
1027       */
1028      myThis->setDisplaySleepDrivenByPM(true);
1029
1030   }
1031   return kIOReturnSuccess;
1032}
1033
1034// powerStateDidChangeTo
1035//
1036// The display wrangler has changed state, so the displays have changed
1037// state, too.  We save the new state.
1038
1039IOReturn IOHIDSystem::powerStateDidChangeTo( IOPMPowerFlags theFlags, unsigned long state, IOService * service)
1040{
1041    IOHID_DEBUG(kIOHIDDebugCode_PowerStateChangeEvent, service, state, theFlags, 0);
1042    if (service == displayManager)
1043    {
1044        displayState = theFlags;
1045        if (theFlags & IOPMDeviceUsable) {
1046            clock_get_uptime(&displayStateChangeDeadline);
1047            ADD_ABSOLUTETIME(&displayStateChangeDeadline,
1048                             &gIOHIDRelativeTickleThresholdAbsoluteTime);
1049            AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0;
1050
1051           // Reset all flags. Flag key release events may not get delivered as they
1052           // come late in system sleep or display sleep process.
1053           updateEventFlags(0);
1054        }
1055        else {
1056             // If the display has transitioned from usable to unusable state
1057             // because of display sleep  then set the deadline before which
1058             // pointer movement can bring the display to usable state.
1059             // Also make sure that this display sleep is not driven by IOPM as part of system sleep
1060
1061           if ( !CMP_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDZeroAbsoluteTime) &&
1062                   (kOSBooleanFalse == rootDomain->copyProperty("DisplayIdleForDemandSleep"))) {
1063             clock_get_uptime(&displaySleepWakeupDeadline);
1064             ADD_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime);
1065           }
1066           displaySleepDrivenByPM = false; // Reset flag for next use
1067        }
1068
1069    }
1070    else if (service == rootDomain)
1071    {
1072        if (theFlags & kIOPMPowerOn)
1073        {
1074            clock_get_uptime(&rootDomainStateChangeDeadline);
1075            ADD_ABSOLUTETIME(&rootDomainStateChangeDeadline, &gIOHIDPowerOnThresoldAbsoluteTime);
1076            ClearCachedMouseButtonStates(cachedButtonStates);
1077        }
1078    }
1079    return IOPMNoErr;
1080}
1081
1082bool IOHIDSystem::genericNotificationHandler(void * handler,
1083                                             IOService * newService,
1084                                             IONotifier * /* notifier */)
1085{
1086    bool result = false;
1087
1088    if (handler && newService && _delayedNotificationSource) {
1089        IOHIDSystem_notificationData    rawData = {(IOCommandGate::Action)handler, newService};
1090        OSData                          *data = OSData::withBytes(&rawData, sizeof(rawData));
1091
1092        if (data) {
1093            newService->retain();
1094            IOLockLock(_delayedNotificationLock);
1095            _delayedNotificationArray->setObject(data);
1096            IOLockUnlock(_delayedNotificationLock);
1097            data->release();
1098            _delayedNotificationSource->setTimeoutUS(1);
1099            result = true;
1100        }
1101    }
1102
1103    return result;
1104}
1105
1106void IOHIDSystem::doProcessNotifications(IOTimerEventSource *sender __unused)
1107{
1108    bool reschedule = false;
1109
1110    while (_delayedNotificationArray->getCount() > 0) {
1111        // retrieve the first item from the queue
1112        IOLockLock(_delayedNotificationLock);
1113        OSData *notificationData = OSDynamicCast(OSData, _delayedNotificationArray->getObject(0));
1114        if (notificationData) {
1115            notificationData->retain();
1116        }
1117        _delayedNotificationArray->removeObject(0);
1118        IOLockUnlock(_delayedNotificationLock);
1119
1120        // process the notification
1121        if (notificationData) {
1122            const IOHIDSystem_notificationData *data = (const IOHIDSystem_notificationData *)notificationData->getBytesNoCopy();
1123            cmdGate->runAction(data->handler, data->newService);
1124            data->newService->release();
1125            notificationData->release();
1126        }
1127    }
1128
1129    if (reschedule) {
1130        _delayedNotificationSource->setTimeoutUS(1);
1131    }
1132}
1133
1134
1135bool IOHIDSystem::handlePublishNotification(
1136            void * target,
1137            IOService * newService )
1138{
1139    IOHIDSystem * self = (IOHIDSystem *) target;
1140
1141    // avoiding OSDynamicCast & dependency on graphics family
1142    if( newService->metaCast("IODisplayWrangler")) {
1143        if( !self->displayManager) {
1144            self->displayManager = newService;
1145            self->displayState = newService->registerInterestedDriver(self);
1146        }
1147        return true;
1148    }
1149
1150    self->attach( newService );
1151
1152    if( OSDynamicCast(IOHIDevice, newService) ||
1153        OSDynamicCast(IOHIDEventService, newService)) {
1154        if (self->ioHIDevices) {
1155            if (self->ioHIDevices->getNextIndexOfObject(newService, 0) == (unsigned)-1)
1156                self->ioHIDevices->setObject(newService);
1157        }
1158
1159        if (OSDynamicCast(IOHIPointing, newService))
1160        {
1161            AppendNewCachedMouseEventForService(self->cachedButtonStates, newService);
1162        }
1163
1164        OSArray * newSystemInfo = OSArray::withArray(self->systemInfo);
1165        if ( newSystemInfo )
1166        {
1167            AppendNewNXSystemInfoForService(newSystemInfo, newService);
1168            self->setProperty(kNXSystemInfoKey, newSystemInfo);
1169            OSSafeReleaseNULL(self->systemInfo);
1170            self->systemInfo = newSystemInfo;
1171        }
1172
1173        if(self->eventsOpen || OSDynamicCast(IOHIKeyboard, newService))
1174            self->registerEventSource( newService );
1175    }
1176
1177    return true;
1178}
1179
1180bool IOHIDSystem::handleTerminateNotification(
1181            void * target,
1182            IOService * service )
1183{
1184    IOHIDSystem * self = (IOHIDSystem *) target;
1185    int index;
1186
1187    if( self->eventsOpen && (
1188        OSDynamicCast(IOHIDevice, service) ||
1189        OSDynamicCast(IOHIDEventService, service)))
1190    {
1191        service->close(self);
1192    }
1193
1194    // <rdar://problem/14116334&14536084&14757282&14775621>
1195    // self->detach(service);
1196
1197    if (self->ioHIDevices) {
1198        if ((index = self->ioHIDevices->getNextIndexOfObject(service, 0)) != -1)
1199            self->ioHIDevices->removeObject(index);
1200    }
1201
1202    OSArray * newSystemInfo = OSArray::withArray(self->systemInfo);
1203    if ( newSystemInfo )
1204    {
1205        RemoveNXSystemInfoForService(newSystemInfo, service);
1206        self->setProperty(kNXSystemInfoKey, newSystemInfo);
1207        OSSafeReleaseNULL(self->systemInfo);
1208        self->systemInfo = newSystemInfo;
1209    }
1210
1211    // RY: Remove this object from the cachedButtonState
1212    if (OSDynamicCast(IOHIPointing, service))
1213    {
1214        // Clear the service button state
1215        AbsoluteTime    ts;
1216        clock_get_uptime(&ts);
1217        if ( (self->displayState & IOPMDeviceUsable) ) {
1218            self->relativePointerEvent(0, 0, 0, ts, service);
1219        }
1220
1221        CachedMouseEventStruct *cachedMouseEvent;
1222        if ((cachedMouseEvent = GetCachedMouseEventForService(self->cachedButtonStates, service)) &&
1223            (cachedMouseEvent->proximityData.proximity.enterProximity))
1224        {
1225            cachedMouseEvent->proximityData.proximity.enterProximity = false;
1226            cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag;
1227            self->proximityEvent(&(cachedMouseEvent->proximityData), ts, service);
1228            cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag;
1229
1230            IOGBounds   bounds = {0, 0, 0, 0};
1231            IOGPoint   newLoc = {0, 0};
1232            self->absolutePointerEvent(0, &newLoc, &bounds, false, 0, 0, ts, service);
1233        }
1234
1235        RemoveCachedMouseEventForService(self->cachedButtonStates, service);
1236    }
1237
1238    return true;
1239}
1240
1241/*
1242 * Free locally allocated resources, and then ourselves.
1243 */
1244void IOHIDSystem::free()
1245{
1246    if (cmdGate) {
1247        evClose();
1248    }
1249
1250    // we are going away. stop the workloop.
1251    if (workLoop) {
1252        workLoop->disableAllEventSources();
1253    }
1254
1255    if (periodicES) {
1256        periodicES->cancelTimeout();
1257
1258        if ( workLoop )
1259            workLoop->removeEventSource( periodicES );
1260
1261        periodicES->release();
1262        periodicES = 0;
1263    }
1264    if (eventConsumerES) {
1265        eventConsumerES->disable();
1266
1267        if ( workLoop )
1268            workLoop->removeEventSource( eventConsumerES );
1269
1270        eventConsumerES->release();
1271        eventConsumerES = 0;
1272    }
1273    if (keyboardEQES) {
1274        keyboardEQES->disable();
1275
1276        if ( workLoop )
1277            workLoop->removeEventSource( keyboardEQES );
1278        keyboardEQES->release();
1279        keyboardEQES = 0;
1280    }
1281
1282    if (_privateData) {
1283        if (_delayedNotificationSource) {
1284            _delayedNotificationSource->cancelTimeout();
1285            if ( workLoop )
1286                workLoop->removeEventSource( _delayedNotificationSource );
1287            _delayedNotificationSource->release();
1288        }
1289        if (_delayedNotificationLock) {
1290            IOLockFree(_delayedNotificationLock);
1291            _delayedNotificationLock = 0;
1292        }
1293        OSSafeReleaseNULL(_delayedNotificationArray);
1294    }
1295
1296
1297    if (evScreen) IOFree( (void *)evScreen, evScreenSize );
1298    evScreen = (void *)0;
1299    evScreenSize = 0;
1300
1301    if (publishNotify) {
1302        publishNotify->remove();
1303        publishNotify = 0;
1304    }
1305    if (gSwitchNotification) {
1306        gSwitchNotification->remove();
1307        gSwitchNotification = 0;
1308    }
1309    if (terminateNotify) {
1310        terminateNotify->remove();
1311        terminateNotify = 0;
1312    }
1313    if (eventPublishNotify) {
1314        eventPublishNotify->remove();
1315        eventPublishNotify = 0;
1316    }
1317    if (eventTerminateNotify) {
1318        eventTerminateNotify->remove();
1319        eventTerminateNotify = 0;
1320    }
1321    if (_displayWranglerMatching) {
1322        _displayWranglerMatching->remove();
1323        _displayWranglerMatching = 0;
1324    }
1325
1326    OSSafeReleaseNULL(cmdGate); // gate is already closed
1327    OSSafeReleaseNULL(workLoop);
1328    OSSafeReleaseNULL(ioHIDevices);
1329    OSSafeReleaseNULL(cachedButtonStates);
1330    OSSafeReleaseNULL(consumedKeys);
1331    OSSafeReleaseNULL(systemInfo);
1332
1333    if ( gKeyboardEQLock ) {
1334        IOLock * lock = gKeyboardEQLock;
1335        IOLockLock(lock);
1336        gKeyboardEQLock = 0;
1337        IOLockUnlock(lock);
1338        IOLockFree(lock);
1339    }
1340
1341    OSSafeReleaseNULL(_hidKeyboardDevice);
1342    OSSafeReleaseNULL(_hidPointingDevice);
1343
1344    if (_privateData) {
1345        _cursorHelper.finalize();
1346        IOFree((void*)_privateData, sizeof(ExpansionData));
1347        _privateData = NULL;
1348    }
1349
1350    super::free();
1351}
1352
1353
1354
1355/*
1356 * Open the driver for business.  This call must be made before
1357 * any other calls to the Event driver.  We can only be opened by
1358 * one user at a time.
1359 */
1360IOReturn IOHIDSystem::evOpen(void)
1361{
1362    IOReturn r = kIOReturnSuccess;
1363
1364    if ( evOpenCalled == true )
1365    {
1366        r = kIOReturnBusy;
1367        goto done;
1368    }
1369    evOpenCalled = true;
1370
1371    if (!evInitialized)
1372    {
1373        evInitialized = true;
1374        // Put code here that is to run on the first open ONLY.
1375    }
1376
1377done:
1378    return r;
1379}
1380
1381IOReturn IOHIDSystem::evClose(void){
1382    return cmdGate->runAction((IOCommandGate::Action)doEvClose);
1383}
1384
1385IOReturn IOHIDSystem::doEvClose(IOHIDSystem *self)
1386                        /* IOCommandGate::Action */
1387{
1388    return self->evCloseGated();
1389}
1390
1391IOReturn IOHIDSystem::evCloseGated(void)
1392{
1393    if ( evOpenCalled == false )
1394        return kIOReturnBadArgument;
1395
1396    evStateChanging = true;
1397
1398    // Early close actions here
1399    if( cursorEnabled)
1400        hideCursor();
1401    cursorStarted = false;
1402    cursorEnabled = false;
1403
1404    // Release the input devices.
1405    detachEventSources();
1406
1407    // Clear screens registry and related data
1408    if ( evScreen != (void *)0 )
1409    {
1410        screens = 0;
1411        lastShmemPtr = (void *)0;
1412    }
1413    // Remove port notification for the eventPort and clear the port out
1414    setEventPortGated(MACH_PORT_NULL);
1415//  ipc_port_release_send(event_port);
1416
1417    // Clear local state to shutdown
1418    evStateChanging = false;
1419    evOpenCalled = false;
1420    eventsOpen = false;
1421
1422    return kIOReturnSuccess;
1423}
1424
1425//
1426// Dispatch state to screens registered with the Event Driver
1427// Pending state changes for a device may be coalesced.
1428//
1429//
1430// This should be run from a command gate action.
1431//
1432void IOHIDSystem::evDispatch(
1433               /* command */ EvCmd evcmd)
1434{
1435    if( !eventsOpen || (evcmd == EVLEVEL) || (evcmd == EVNOP))
1436        return;
1437
1438    for( int i = 0; i < screens; i++ ) {
1439        bool onscreen = (0 != (cursorScreens & (1 << i)));
1440
1441        if (onscreen) {
1442            EvScreen *esp = &((EvScreen*)evScreen)[i];
1443
1444            if ( esp->instance ) {
1445                IOGPoint p;
1446                p.x = evg->screenCursorFixed.x / 256;   // Copy from shmem.
1447                p.y = evg->screenCursorFixed.y / 256;
1448
1449                switch ( evcmd )
1450                {
1451                    case EVMOVE:
1452                        esp->instance->moveCursor(&p, evg->frame);
1453                        break;
1454
1455                    case EVSHOW:
1456                        esp->instance->showCursor(&p, evg->frame);
1457                        break;
1458
1459                    case EVHIDE:
1460                        esp->instance->hideCursor();
1461                        break;
1462
1463                    default:
1464                        // should never happen
1465                        break;
1466                }
1467            }
1468        }
1469    }
1470}
1471
1472//
1473// Dispatch mechanism for special key press.  If a port has been registered,
1474// a message is built to be sent out to that port notifying that the key has
1475// changed state.  A level in the range 0-64 is provided for convenience.
1476//
1477void IOHIDSystem::evSpecialKeyMsg(unsigned key,
1478          /* direction */ unsigned dir,
1479          /* flags */     unsigned f,
1480          /* level */     unsigned l)
1481{
1482    mach_port_t dst_port;
1483    struct evioSpecialKeyMsg *msg;
1484
1485    static const struct evioSpecialKeyMsg init_msg =
1486        { { MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, // mach3xxx, is the right?
1487                        MACH_MSG_TYPE_MAKE_SEND),   // mach_msg_bits_t  msgh_bits;
1488            sizeof (struct evioSpecialKeyMsg),      // mach_msg_size_t  msgh_size;
1489            MACH_PORT_NULL,             // mach_port_t  msgh_remote_port;
1490            MACH_PORT_NULL,             // mach_port_t  msgh_local_port;
1491            0,                      // mach_msg_size_t msgh_reserved;
1492            EV_SPECIAL_KEY_MSG_ID           // mach_msg_id_t    msgh_id;
1493            },
1494            0,  /* key */
1495            0,  /* direction */
1496            0,  /* flags */
1497            0   /* level */
1498        };
1499
1500    if ( (dst_port = specialKeyPort(key)) == MACH_PORT_NULL )
1501        return;
1502    msg = (struct evioSpecialKeyMsg *) IOMalloc(
1503                sizeof (struct evioSpecialKeyMsg) );
1504    if ( msg == NULL )
1505        return;
1506
1507    // Initialize the message.
1508    bcopy( &init_msg, msg, sizeof (struct evioSpecialKeyMsg) );
1509    msg->Head.msgh_remote_port = dst_port;
1510    msg->key = key;
1511    msg->direction = dir;
1512    msg->flags = f;
1513    msg->level = l;
1514
1515    // Send the message out from the command gate.
1516        cmdGate->runAction((IOCommandGate::Action)doSpecialKeyMsg,(void*)msg);
1517}
1518
1519//
1520// Reset instance variables to their default state for mice/pointers
1521//
1522
1523void IOHIDSystem::_resetMouseParameters(void)
1524{
1525    if ( eventsOpen == false )
1526        return;
1527
1528    OSDictionary    *tempDict = OSDictionary::withCapacity(3);
1529    UInt64      nano;
1530
1531    nanoseconds_to_absolutetime( EV_DCLICKTIME, &clickTimeThresh);
1532    clickSpaceThresh.x = clickSpaceThresh.y = EV_DCLICKSPACE;
1533    AbsoluteTime_to_scalar( &clickTime) = 0;
1534    clickLoc.x = clickLoc.y = -EV_DCLICKSPACE;
1535    clickState = 1;
1536
1537    if (tempDict) {
1538        UInt32  tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y};
1539        makeInt32ArrayParamProperty( tempDict, kIOHIDClickSpaceKey,
1540                                    tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) );
1541
1542        nano = EV_DCLICKTIME;
1543        makeNumberParamProperty( tempDict, kIOHIDClickTimeKey,
1544                                nano, 64 );
1545
1546        setParamProperties(tempDict);
1547
1548        tempDict->release();
1549    }
1550}
1551
1552////////////////////////////////////////////////////////////////////////////
1553//#define LOG_SCREEN_REGISTRATION
1554#ifdef LOG_SCREEN_REGISTRATION
1555#warning LOG_SCREEN_REGISTRATION is defined
1556#define log_screen_reg(fmt, args...)  kprintf(">>> " fmt, args)
1557#else
1558#define log_screen_reg(fmt, args...)
1559#endif
1560
1561////////////////////////////////////////////////////////////////////////////
1562int
1563IOHIDSystem::registerScreen(IOGraphicsDevice * io_gd,
1564                            IOGBounds * boundsPtr,
1565                            IOGBounds * virtualBoundsPtr)
1566{
1567    int result = -1;
1568
1569    // If we are not open for business, fail silently
1570    if (eventsOpen) {
1571        // for this version of the call, these must all be supplied
1572        if (!io_gd || !boundsPtr || !virtualBoundsPtr) {
1573            IOLog("%s invalid call %p %p %p\n", __PRETTY_FUNCTION__, io_gd, boundsPtr, virtualBoundsPtr);
1574        }
1575        else {
1576            UInt32 index;
1577            IOReturn ret = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen,
1578                                               this, io_gd, boundsPtr, virtualBoundsPtr, &index);
1579            if (ret == kIOReturnSuccess) {
1580                result = SCREENTOKEN + index;
1581            }
1582            else {
1583                IOLog("%s failed %08x\n", __PRETTY_FUNCTION__, ret);
1584            }
1585        }
1586    }
1587    log_screen_reg("%s: registered token %d\n", __PRETTY_FUNCTION__, result);
1588    return result;
1589}
1590
1591////////////////////////////////////////////////////////////////////////////
1592IOReturn
1593IOHIDSystem::extRegisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*)
1594{
1595    IOReturn result = kIOReturnBadArgument;
1596    if (token_ptr) {
1597        SInt32 index;
1598        UInt64 *token = (UInt64 *)token_ptr;
1599        result = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen,
1600                                     this, NULL, NULL, NULL, &index);
1601        if ((index >= 0) && (index < EV_MAX_SCREENS)) {
1602            *token = SCREENTOKEN + index;
1603        }
1604        else {
1605            *token = 0;
1606            if (result == kIOReturnSuccess) {
1607                result = kIOReturnInternalError;
1608                IOLog("IOHIDSystem tried to return an invalid token with no error\n");
1609            }
1610        }
1611        log_screen_reg("%s: registered token %lld on %x\n", __PRETTY_FUNCTION__, *token, result);
1612    }
1613    return result;
1614}
1615
1616////////////////////////////////////////////////////////////////////////////
1617IOReturn
1618IOHIDSystem::doRegisterScreen(IOHIDSystem *self,
1619                              IOGraphicsDevice *io_gd,
1620                              IOGBounds *bounds,
1621                              IOGBounds *virtualBounds,
1622                              void *index)
1623{
1624    return self->registerScreenGated(io_gd, bounds, virtualBounds, (SInt32*)index);
1625}
1626
1627////////////////////////////////////////////////////////////////////////////
1628//#define LOG_SCROLL_STATE
1629#ifdef LOG_SCROLL_STATE
1630#   define log_scroll_state(s, ...)     kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__)
1631#   define log_scroll_state_b(s, ...)   kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__)
1632#else
1633#   define log_scroll_state(s, ...)
1634#   define log_scroll_state_b(s, ...)
1635#endif
1636
1637////////////////////////////////////////////////////////////////////////////
1638IOReturn
1639IOHIDSystem::registerScreenGated(IOGraphicsDevice *io_gd,
1640                                 IOGBounds *boundsPtr,
1641                                 IOGBounds *virtualBoundsPtr,
1642                                 SInt32 *index)
1643{
1644    EvScreen *screen_ptr = NULL;
1645    OSNumber *num = NULL;
1646    IOReturn result = kIOReturnSuccess;
1647    *index = -1;
1648
1649    if ( lastShmemPtr == (void *)0 )
1650        lastShmemPtr = evs;
1651
1652    /* shmemSize and bounds already set */
1653    log_screen_reg("%s %p %p %p\n", __func__, io_gd, boundsPtr, virtualBoundsPtr);
1654
1655    // locate next available screen
1656    for (int i = 0; (i < EV_MAX_SCREENS) && (screen_ptr == NULL); i++) {
1657        screen_ptr = &((EvScreen*)evScreen)[i];
1658
1659        if (io_gd && (screen_ptr->instance == io_gd)) {
1660            // Empty slot.
1661            log_screen_reg("%s refound at index %d\n", __func__, i);
1662            *index = i;
1663        }
1664        else if (screen_ptr->creator_pid) {
1665            proc_t isStillAlive = proc_find(screen_ptr->creator_pid);
1666            if (isStillAlive) {
1667                // Still in use.
1668                screen_ptr = NULL;
1669                proc_rele(isStillAlive);
1670            }
1671            else {
1672                // Dead head.
1673                IOLog("IOHIDSystem::%s: Screen %d recycled from pid %d\n", __func__, i, screen_ptr->creator_pid);
1674                *index = i;
1675                screen_ptr->creator_pid = 0;
1676                screen_ptr->displayBounds = NULL;
1677                screen_ptr->desktopBounds = NULL;
1678            }
1679        }
1680        else if (screen_ptr->instance) {
1681            // Still in use.
1682            screen_ptr = NULL; // try the next one
1683        }
1684        else {
1685            // New slot
1686            log_screen_reg("%s new index at %d\n", __func__, i);
1687            *index = i;
1688        }
1689    }
1690
1691    if (!screen_ptr) {
1692        IOLog("IOHIDSystem::%s: No space found for new screen\n", __func__);
1693        result = kIOReturnNoResources;
1694    }
1695    else if (io_gd && boundsPtr && virtualBoundsPtr) {
1696        // called by video driver. they maintain their own bounds.
1697        screen_ptr->instance = io_gd;
1698        screen_ptr->displayBounds = boundsPtr;
1699        screen_ptr->desktopBounds = virtualBoundsPtr;
1700        screen_ptr->creator_pid = 0; // kernel made
1701
1702        // Update our idea of workSpace bounds
1703        if ( boundsPtr->minx < workSpace.minx )
1704            workSpace.minx = boundsPtr->minx;
1705        if ( boundsPtr->miny < workSpace.miny )
1706            workSpace.miny = boundsPtr->miny;
1707        if ( boundsPtr->maxx < workSpace.maxx )
1708            workSpace.maxx = boundsPtr->maxx;
1709        if ( screen_ptr->displayBounds->maxy < workSpace.maxy )
1710            workSpace.maxy = boundsPtr->maxy;
1711
1712        // perform other bookkeeping
1713        num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorFramesKey);
1714        if(OSDynamicCast(OSNumber, num) &&
1715           (num->unsigned32BitValue() > maxWaitCursorFrame)) {
1716            firstWaitCursorFrame = 0;
1717            maxWaitCursorFrame   = num->unsigned32BitValue();
1718            evg->lastFrame       = maxWaitCursorFrame;
1719        }
1720        OSSafeReleaseNULL(num);
1721        num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorPeriodKey);
1722        if( OSDynamicCast(OSNumber, num) ) {
1723            clock_interval_to_absolutetime_interval(num->unsigned32BitValue(), kNanosecondScale, &_cursorWaitDelta);
1724        }
1725        OSSafeReleaseNULL(num);
1726    }
1727    else if (!io_gd && !boundsPtr && !virtualBoundsPtr) {
1728        // called by window server. we maintain the bounds.
1729        screen_ptr->displayBounds = (IOGBounds*)screen_ptr->scratch;
1730        screen_ptr->desktopBounds = screen_ptr->displayBounds + 1;
1731        screen_ptr->creator_pid = proc_selfpid();
1732
1733        // default the bounds to lala land
1734        screen_ptr->displayBounds->minx = screen_ptr->desktopBounds->minx = screen_ptr->displayBounds->miny = screen_ptr->desktopBounds->miny = -30001;
1735        screen_ptr->displayBounds->maxx = screen_ptr->desktopBounds->maxx = screen_ptr->displayBounds->maxy = screen_ptr->desktopBounds->maxy = -30000;
1736    }
1737    else {
1738        result = kIOReturnBadArgument;
1739    }
1740
1741    if (result == kIOReturnSuccess) {
1742        log_screen_reg(">>> display %d is for %d\n", *index, screen_ptr->creator_pid);
1743        if (*index >= screens) {
1744            screens = 1 + *index;
1745        }
1746    }
1747
1748    return result;
1749}
1750
1751////////////////////////////////////////////////////////////////////////////
1752void IOHIDSystem::unregisterScreen(int token) {
1753    uintptr_t index = token - SCREENTOKEN;
1754    log_screen_reg("%s: unregistering token %d\n", __PRETTY_FUNCTION__, token);
1755    if (index < EV_MAX_SCREENS) {
1756        IOReturn ret = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index);
1757        if (ret != kIOReturnSuccess) {
1758            IOLog("%s recieved %08x for token %d.\n", __PRETTY_FUNCTION__, ret, token);
1759        }
1760    }
1761    else {
1762        IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, token);
1763    }
1764}
1765
1766////////////////////////////////////////////////////////////////////////////
1767IOReturn
1768IOHIDSystem::extUnregisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*)
1769{
1770    IOReturn result = kIOReturnSuccess;
1771    uintptr_t token = (uintptr_t)token_ptr;
1772    uintptr_t index = token - SCREENTOKEN;
1773    if (index < EV_MAX_SCREENS) {
1774        result = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index);
1775    }
1776    else {
1777        IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token);
1778        result = kIOReturnBadArgument;
1779    }
1780    log_screen_reg("%s: unregistering token %lu on %x\n", __PRETTY_FUNCTION__, token, result);
1781
1782    return result;
1783}
1784
1785////////////////////////////////////////////////////////////////////////////
1786IOReturn IOHIDSystem::doUnregisterScreen (IOHIDSystem *self, void * arg0, void *arg1)
1787                        /* IOCommandGate::Action */
1788{
1789    uintptr_t index = (uintptr_t) arg0;
1790    uintptr_t internal = (uintptr_t) arg1;
1791
1792    return self->unregisterScreenGated(index, internal);
1793}
1794
1795////////////////////////////////////////////////////////////////////////////
1796IOReturn IOHIDSystem::unregisterScreenGated(int index, bool internal)
1797{
1798    IOReturn result = kIOReturnSuccess;
1799    log_screen_reg("%s %d %d %d\n", __func__, index, internal, screens);
1800
1801    if ( eventsOpen == false || index >= screens ) {
1802        result = kIOReturnNoResources;
1803    }
1804    else {
1805        EvScreen *screen_ptr = ((EvScreen*)evScreen)+index;
1806
1807        if (!screen_ptr->displayBounds) {
1808            IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, index);
1809            result = kIOReturnBadArgument;
1810        }
1811        else if (internal && !screen_ptr->instance) {
1812            IOLog("%s called internally on an external device %d\n", __PRETTY_FUNCTION__, index);
1813            result = kIOReturnNoDevice;
1814        }
1815        else if (!internal && screen_ptr->instance) {
1816            IOLog("%s called externally on an internal device %d\n", __PRETTY_FUNCTION__, index);
1817            result = kIOReturnNotPermitted;
1818        }
1819        else {
1820            hideCursor();
1821
1822            // clear the variables
1823            screen_ptr->instance = NULL;
1824            screen_ptr->desktopBounds = NULL;
1825            screen_ptr->displayBounds = NULL;
1826            screen_ptr->creator_pid = 0;
1827
1828            // Put the cursor someplace reasonable if it was on the destroyed screen
1829            cursorScreens &= ~(1 << index);
1830            // This will jump the cursor back on screen
1831            setCursorPosition((IOGPoint *)&evg->cursorLoc, true);
1832
1833            showCursor();
1834        }
1835    }
1836
1837    return result;
1838}
1839
1840////////////////////////////////////////////////////////////////////////////
1841IOReturn
1842IOHIDSystem::extSetVirtualDisplayBounds(void* token_ptr,void* minx,void* maxx,void* miny,void* maxy,void*)
1843{
1844    IOReturn result = kIOReturnSuccess;
1845    uintptr_t token = (uintptr_t)token_ptr;
1846    uintptr_t index = token - SCREENTOKEN;
1847    log_screen_reg("%s: set bounds on token %lu\n", __PRETTY_FUNCTION__, token);
1848    if (index < EV_MAX_SCREENS) {
1849        IOGBounds tempBounds = { (uintptr_t) minx, (uintptr_t) maxx, (uintptr_t) miny, (uintptr_t) maxy };
1850        result = cmdGate->runAction((IOCommandGate::Action)doSetDisplayBounds, (void*) index, (void*) &tempBounds);
1851    }
1852    else {
1853        IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token);
1854        result = kIOReturnBadArgument;
1855    }
1856
1857    return result;
1858}
1859
1860////////////////////////////////////////////////////////////////////////////
1861IOReturn
1862IOHIDSystem::doSetDisplayBounds (IOHIDSystem *self, void * arg0, void * arg1)
1863{
1864    uintptr_t index = (uintptr_t) arg0;
1865    IOGBounds *tempBounds = (IOGBounds*) arg1;
1866
1867    return self->setDisplayBoundsGated(index, tempBounds);
1868}
1869
1870////////////////////////////////////////////////////////////////////////////
1871IOReturn
1872IOHIDSystem::setDisplayBoundsGated (UInt32 index, IOGBounds *tempBounds)
1873{
1874    IOReturn result = kIOReturnSuccess;
1875    log_screen_reg("%s ((%d,%d),(%d,%d))\n", __func__, tempBounds->minx, tempBounds->miny, tempBounds->maxx, tempBounds->maxy);
1876
1877    if ( eventsOpen == false || index >= (UInt32)screens ) {
1878        result = kIOReturnNoResources;
1879    }
1880    else {
1881        EvScreen *screen_ptr = ((EvScreen*)evScreen)+index;
1882
1883        if (screen_ptr->instance) {
1884            IOLog("%s called on an internal device %d\n", __PRETTY_FUNCTION__, (int)index);
1885            result = kIOReturnNotPermitted;
1886        }
1887        else if (!screen_ptr->displayBounds || !screen_ptr->desktopBounds) {
1888            IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, (int)index);
1889            result = kIOReturnBadArgument;
1890        }
1891        else {
1892            // looks good
1893            hideCursor();
1894            *(screen_ptr->displayBounds) = *(screen_ptr->desktopBounds) = *tempBounds;
1895            // Put the cursor someplace reasonable if it was on the moved screen
1896            cursorScreens &= ~(1 << index);
1897            // This will jump the cursor back on screen
1898            setCursorPosition((IOGPoint *)&evg->cursorLoc, true);
1899            showCursor();
1900        }
1901    }
1902    return result;
1903}
1904
1905////////////////////////////////////////////////////////////////////////////
1906/* Member of EventClient protocol
1907 *
1908 * Absolute position input devices and some specialized output devices
1909 * may need to know the bounding rectangle for all attached displays.
1910 * The following method returns a IOGBounds* for the workspace.  Please note
1911 * that the bounds are kept as signed values, and that on a multi-display
1912 * system the minx and miny values may very well be negative.
1913 */
1914IOGBounds * IOHIDSystem::workspaceBounds()
1915{
1916    return &workSpace;
1917}
1918
1919IOReturn IOHIDSystem::registerEventQueue(IODataQueue * queue)
1920{
1921    return cmdGate->runAction((IOCommandGate::Action)doRegisterEventQueue, (void *)queue);
1922}
1923
1924IOReturn IOHIDSystem::doRegisterEventQueue (IOHIDSystem *self, void * arg0)
1925                        /* IOCommandGate::Action */
1926{
1927    return self->registerEventQueueGated((IODataQueue *)arg0);
1928}
1929
1930IOReturn IOHIDSystem::registerEventQueueGated(void * p1)
1931{
1932    IODataQueue * queue = (IODataQueue *)p1;
1933    if ( !queue )
1934        return kIOReturnBadArgument;
1935
1936    if ( !dataQueueSet )
1937        dataQueueSet = OSSet::withCapacity(4);
1938
1939    dataQueueSet->setObject(queue);
1940
1941    return kIOReturnSuccess;
1942}
1943
1944IOReturn IOHIDSystem::unregisterEventQueue(IODataQueue * queue)
1945{
1946    return cmdGate->runAction((IOCommandGate::Action)doUnregisterEventQueue, (void *)queue);
1947}
1948
1949IOReturn IOHIDSystem::doUnregisterEventQueue (IOHIDSystem *self, void * arg0)
1950                        /* IOCommandGate::Action */
1951{
1952    return self->unregisterEventQueueGated((IODataQueue *)arg0);
1953}
1954
1955IOReturn IOHIDSystem::unregisterEventQueueGated(void * p1)
1956{
1957    IODataQueue * queue = (IODataQueue *)p1;
1958
1959    if ( !queue )
1960        return kIOReturnBadArgument;
1961
1962    if ( dataQueueSet )
1963        dataQueueSet->removeObject(queue);
1964
1965    return kIOReturnSuccess;
1966}
1967
1968IOReturn IOHIDSystem::createShmem(void* p1, void*, void*, void*, void*, void*)
1969{                                                                    // IOMethod
1970    return cmdGate->runAction((IOCommandGate::Action)doCreateShmem, p1);
1971}
1972
1973IOReturn IOHIDSystem::doCreateShmem (IOHIDSystem *self, void * arg0)
1974                        /* IOCommandGate::Action */
1975{
1976    return self->createShmemGated(arg0);
1977}
1978
1979IOReturn IOHIDSystem::createShmemGated(void* p1)
1980{
1981
1982    int                 shmemVersion = (uintptr_t)p1;
1983    IOByteCount         size;
1984    bool                clean = false;
1985
1986    if ( shmemVersion < kIOHIDLastCompatibleShmemVersion ) {
1987        IOLog("IOHIDSystem::createShmemGated called with low version: %d < %d\n", shmemVersion, kIOHIDLastCompatibleShmemVersion);
1988        return kIOReturnUnsupported;
1989    }
1990
1991    if ( shmemVersion > kIOHIDCurrentShmemVersion ) {
1992        IOLog("IOHIDSystem::createShmemGated called with hi version: %d > %d\n", shmemVersion, kIOHIDCurrentShmemVersion);
1993        return kIOReturnUnsupported;
1994    }
1995
1996    if ( 0 == globalMemory) {
1997
1998        size = sizeof(EvOffsets) + sizeof(EvGlobals);
1999        globalMemory = IOBufferMemoryDescriptor::withOptions( kIODirectionNone | kIOMemoryKernelUserShared, size );
2000
2001        if ( !globalMemory)
2002            return kIOReturnNoMemory;
2003
2004        shmem_addr = (uintptr_t) globalMemory->getBytesNoCopy();
2005        shmem_size = size;
2006
2007        clean = true;
2008    }
2009
2010    initShmem(clean);
2011
2012    return kIOReturnSuccess;
2013}
2014
2015// Initialize the shared memory area.
2016//
2017// This should be run from a command gate action.
2018void IOHIDSystem::initShmem(bool clean)
2019{
2020    int  i;
2021    EvOffsets *eop;
2022    int oldFlags = 0;
2023
2024    /* top of sharedMem is EvOffsets structure */
2025    eop = (EvOffsets *) shmem_addr;
2026
2027    if (!clean) {
2028        oldFlags = ((EvGlobals *)((char *)shmem_addr + sizeof(EvOffsets)))->eventFlags;
2029    }
2030
2031    bzero( (void*)shmem_addr, shmem_size);
2032
2033    /* fill in EvOffsets structure */
2034    eop->evGlobalsOffset = sizeof(EvOffsets);
2035    eop->evShmemOffset = eop->evGlobalsOffset + sizeof(EvGlobals);
2036
2037    /* find pointers to start of globals and private shmem region */
2038    evg = (EvGlobals *)((char *)shmem_addr + eop->evGlobalsOffset);
2039    evs = (void *)((char *)shmem_addr + eop->evShmemOffset);
2040
2041    evg->version = kIOHIDCurrentShmemVersion;
2042    evg->structSize = sizeof( EvGlobals);
2043
2044    /* Set default wait cursor parameters */
2045    evg->waitCursorEnabled = TRUE;
2046    evg->globalWaitCursorEnabled = TRUE;
2047    evg->lastFrame = maxWaitCursorFrame;
2048    evg->waitThreshold = (12 * EV_TICKS_PER_SEC) / 10;
2049
2050    evg->buttons = 0;
2051    evg->eNum = INITEVENTNUM;
2052    evg->eventFlags = oldFlags;
2053
2054    evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32();
2055    evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32();
2056    evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8();
2057    evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8();
2058    evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8();
2059    evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8();
2060
2061    evg->updateCursorPositionFromFixed = 0;
2062    evg->logCursorUpdates = 0;
2063    evg->dontCoalesce = 0;
2064    evg->dontWantCoalesce = 0;
2065    evg->wantPressure = 0;
2066    evg->wantPrecision = 0;
2067    evg->mouseRectValid = 0;
2068    evg->movedMask = 0;
2069    evg->cursorSema = OS_SPINLOCK_INIT;
2070    evg->waitCursorSema = OS_SPINLOCK_INIT;
2071
2072    /* Set up low-level queues */
2073    lleqSize = LLEQSIZE;
2074    for (i=lleqSize; --i != -1; ) {
2075        evg->lleq[i].event.type = 0;
2076        AbsoluteTime_to_scalar(&evg->lleq[i].event.time) = 0;
2077        evg->lleq[i].event.flags = 0;
2078        evg->lleq[i].sema = OS_SPINLOCK_INIT;
2079        evg->lleq[i].next = i+1;
2080    }
2081    evg->LLELast = 0;
2082    evg->lleq[lleqSize-1].next = 0;
2083    evg->LLEHead = evg->lleq[evg->LLELast].next;
2084    evg->LLETail = evg->lleq[evg->LLELast].next;
2085
2086    _cursorLogTimed();
2087
2088    // Set eventsOpen last to avoid race conditions.
2089    eventsOpen = true;
2090}
2091
2092//
2093// Set the event port.  The event port is both an ownership token
2094// and a live port we hold send rights on.  The port is owned by our client,
2095// the WindowServer.  We arrange to be notified on a port death so that
2096// we can tear down any active resources set up during this session.
2097// An argument of PORT_NULL will cause us to forget any port death
2098// notification that's set up.
2099//
2100// This should be run from a command gate action.
2101//
2102void IOHIDSystem::setEventPort(mach_port_t port)
2103{
2104    if ((eventPort != port) && (workLoop))
2105        workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doSetEventPort, this, (void*)port);
2106}
2107
2108IOReturn IOHIDSystem::doSetEventPort(IOHIDSystem *self, void *port_void, void *arg1 __unused, void *arg2 __unused, void *arg3 __unused)
2109{
2110    self->setEventPortGated((mach_port_t)port_void);
2111    return kIOReturnSuccess;
2112}
2113
2114void IOHIDSystem::setEventPortGated(mach_port_t port)
2115{
2116    static struct _eventMsg init_msg = { {
2117            // mach_msg_bits_t  msgh_bits;
2118            MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
2119            // mach_msg_size_t  msgh_size;
2120            sizeof (struct _eventMsg),
2121            // mach_port_t  msgh_remote_port;
2122            MACH_PORT_NULL,
2123            // mach_port_t  msgh_local_port;
2124            MACH_PORT_NULL,
2125            // mach_msg_size_t  msgh_reserved;
2126            0,
2127            // mach_msg_id_t    msgh_id;
2128            0
2129        } };
2130
2131    init_msg.h.msgh_remote_port = port;
2132
2133    if ( eventMsg == NULL )
2134        eventMsg = IOMalloc( sizeof (struct _eventMsg) );
2135
2136    // Initialize the events available message.
2137    *((struct _eventMsg *)eventMsg) = init_msg;
2138    eventPort = port;
2139
2140        // RY: Added this check so that the event consumer
2141        // can get notified if the queue in not empty.
2142        // Otherwise the event consumer will never get a
2143        // notification.
2144        if (EventsInQueue())
2145            kickEventConsumer();
2146}
2147
2148//
2149// Set the port to be used for a special key notification.  This could be more
2150// robust about letting ports be set...
2151//
2152IOReturn IOHIDSystem::setSpecialKeyPort(
2153                        /* keyFlavor */ int         special_key,
2154                        /* keyPort */   mach_port_t key_port)
2155{
2156    if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
2157        _specialKeyPort[special_key] = key_port;
2158    return kIOReturnSuccess;
2159}
2160
2161mach_port_t IOHIDSystem::specialKeyPort(int special_key)
2162{
2163    if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
2164        return _specialKeyPort[special_key];
2165    return MACH_PORT_NULL;
2166}
2167
2168//
2169// Set the port to be used for stack shot
2170//
2171void IOHIDSystem::setStackShotPort(mach_port_t port)
2172{
2173    stackShotPort = port;
2174
2175    static _stackShotMessage init_msg =
2176    {
2177        {                                           // mach_msg_header_t    header
2178            MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),  // mach_msg_bits_t      msgh_bits;
2179            sizeof (init_msg),                          // mach_msg_size_t      msgh_size;
2180            MACH_PORT_NULL,                             // mach_port_t          msgh_remote_port;
2181            MACH_PORT_NULL,                             // mach_port_t          msgh_local_port;
2182            0,                                          // mach_msg_size_t      msgh_reserved;
2183            0                                           // mach_msg_id_t        msgh_id;
2184        },
2185        0                                           // UInt32               flavor
2186    };
2187
2188    if ( stackShotMsg ) {
2189        IOFree(stackShotMsg, sizeof(_stackShotMessage));
2190        stackShotMsg = NULL;
2191    }
2192
2193    if ( stackShotPort ) {
2194        if ( !(stackShotMsg = IOMalloc(sizeof(_stackShotMessage))) )
2195            return;
2196
2197        // Initialize the events available message.
2198        init_msg.header.msgh_remote_port = stackShotPort;
2199        *((_stackShotMessage*)stackShotMsg) = init_msg;
2200    }
2201}
2202
2203UInt32 IOHIDSystem::eventFlags()
2204{
2205    return evg ? (evg->eventFlags) : 0;
2206}
2207
2208void IOHIDSystem::dispatchEvent(IOHIDEvent *event, IOOptionBits options __unused)
2209{
2210    if ( !event || !dataQueueSet)
2211        return;
2212
2213    OSCollectionIterator *      iterator    = OSCollectionIterator::withCollection(dataQueueSet);
2214    IOHIDEventServiceQueue *    dataQueue   = NULL;
2215
2216    if ( !iterator )
2217        return;
2218
2219    while ((dataQueue = OSDynamicCast(IOHIDEventServiceQueue, iterator->getNextObject()))) {
2220        dataQueue->enqueueEvent(event);
2221    }
2222
2223    iterator->release();
2224
2225}
2226
2227void IOHIDSystem::updateHidActivity()
2228{
2229#if !TARGET_OS_EMBEDDED
2230    clock_get_uptime(&_lastTickleTime);
2231    if (_hidActivityIdle)
2232        thread_call_enter(_hidActivityThread);
2233#endif
2234}
2235
2236void IOHIDSystem::hidActivityChecker( )
2237{
2238    cmdGate->runAction((IOCommandGate::Action)reportUserHidActivity, NULL);
2239}
2240
2241void IOHIDSystem::reportUserHidActivity(IOHIDSystem *self, void *args )
2242{
2243    self->reportUserHidActivityGated(args);
2244}
2245
2246void IOHIDSystem::reportUserHidActivityGated(void *args __unused)
2247{
2248    AbsoluteTime deadline = 0;
2249    AbsoluteTime ts;
2250    static AbsoluteTime  idleHidActivity = 0;
2251
2252    if (!idleHidActivity)
2253        nanoseconds_to_absolutetime(IDLE_HID_ACTIVITY_NSECS, &idleHidActivity);
2254
2255
2256    clock_get_uptime(&ts);
2257    if ((ts-_lastTickleTime)  < idleHidActivity) {
2258        if (_hidActivityIdle) {
2259            _hidActivityIdle = false;
2260            messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle );
2261        }
2262        clock_absolutetime_interval_to_deadline((idleHidActivity+_lastTickleTime-ts), &deadline);
2263
2264        thread_call_enter_delayed(_hidActivityThread, deadline);
2265    }
2266    else if ( !_hidActivityIdle ) {
2267        _hidActivityIdle = true;
2268        messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle );
2269    }
2270}
2271
2272IOReturn IOHIDSystem::extGetUserHidActivityState(void *arg0,void*,void*,void*,void*,void*)
2273{
2274    return cmdGate->runAction((IOCommandGate::Action)getUserHidActivityState, arg0);
2275}
2276
2277IOReturn IOHIDSystem::getUserHidActivityState(IOHIDSystem *self, void *arg0)
2278{
2279    return self->getUserHidActivityStateGated(arg0);
2280}
2281
2282IOReturn IOHIDSystem::getUserHidActivityStateGated(void *state)
2283{
2284    if (state) {
2285        *((uint64_t*)state) = _hidActivityIdle ? 1 : 0;
2286        return kIOReturnSuccess;
2287    }
2288    return kIOReturnBadArgument;
2289}
2290
2291//
2292// Helper functions for postEvent
2293//
2294static inline int myAbs(int a) { return(a > 0 ? a : -a); }
2295
2296short IOHIDSystem::getUniqueEventNum()
2297{
2298    while (++evg->eNum == NULLEVENTNUM)
2299    ; /* sic */
2300    return(evg->eNum);
2301}
2302
2303// postEvent
2304//
2305// This routine actually places events in the event queue which is in
2306// the EvGlobals structure.  It is called from all parts of the ev
2307// driver.
2308//
2309// This should be run from a command gate action.
2310//
2311
2312void IOHIDSystem::postEvent(int           what,
2313             /* at */       IOFixedPoint64 *location,
2314             /* atTime */   AbsoluteTime  ts,
2315             /* withData */ NXEventData * myData,
2316             /* sender */   OSObject *    sender,
2317             /* extPID */   UInt32        extPID,
2318             /* processKEQ*/bool          processKEQ)
2319{
2320    // Clear out the keyboard queue up until this TS.  This should keep
2321    // the events in order.
2322    PROFILE_TRACE(7);
2323    if ( processKEQ )
2324        processKeyboardEQ(this, &ts);
2325
2326    NXEQElement * theHead = (NXEQElement *) &evg->lleq[evg->LLEHead];
2327    NXEQElement * theLast = (NXEQElement *) &evg->lleq[evg->LLELast];
2328    NXEQElement * theTail = (NXEQElement *) &evg->lleq[evg->LLETail];
2329    int         wereEvents;
2330
2331    if (CMP_ABSOLUTETIME(&ts, &lastEventTime) < 0) {
2332        ts = lastEventTime;
2333    }
2334    lastEventTime = ts;
2335
2336    // dispatch new event
2337    IOHIDEvent * event = IOHIDEvent::withEventData(ts, what, myData);
2338    if ( event ) {
2339        dispatchEvent(event);
2340        event->release();
2341    }
2342
2343    /* Some events affect screen dimming (idle time) */
2344    if (EventCodeMask(what) & NX_UNDIMMASK) {
2345        lastUndimEvent = ts;
2346    }
2347
2348    wereEvents = EventsInQueue();
2349
2350    xpr_ev_post("postEvent: what %d, X %d Y %d Q %d, needKick %d\n", what,location->x,location->y, EventsInQueue(), needToKickEventConsumer);
2351    IOHID_DEBUG(kIOHIDDebugCode_PostEvent, what, theHead, theTail, sender);
2352
2353    if ((!evg->dontCoalesce) /* Coalescing enabled */
2354            && (theHead != theTail)
2355            && (theLast->event.type == what)
2356            && (EventCodeMask(what) & COALESCEEVENTMASK)
2357            && OSSpinLockTry(&theLast->sema)) {
2358        /* coalesce events */
2359        theLast->event.location.x = location->xValue().as64();
2360        theLast->event.location.y = location->yValue().as64();
2361        absolutetime_to_nanoseconds(ts, &theLast->event.time);
2362        if (myData != NULL)
2363            theLast->event.data = *myData;
2364        OSSpinLockUnlock(&theLast->sema);
2365    }
2366    else if (theTail->next != evg->LLEHead) {
2367        /* store event in tail */
2368        theTail->event.type         = what;
2369        // <rdar://problem/12682920> Task: Switch event.service_id to use registry ID
2370        // theTail->event.service_id   = (uintptr_t)sender;
2371        theTail->event.service_id = 0;
2372        if (sender) {
2373            IORegistryEntry *entry = OSDynamicCast(IORegistryEntry, sender);
2374            if (entry) {
2375                theTail->event.service_id = (uintptr_t)entry->getRegistryEntryID();
2376            }
2377        }
2378        theTail->event.ext_pid      = extPID;
2379        theTail->event.location.x   = location->xValue().as64();
2380        theTail->event.location.y   = location->yValue().as64();
2381        theTail->event.flags        = evg->eventFlags;
2382        absolutetime_to_nanoseconds(ts, &theLast->event.time);
2383        theTail->event.window = 0;
2384
2385        if (myData != NULL)
2386            theTail->event.data = *myData;
2387
2388        switch (what) {
2389            case NX_LMOUSEDOWN:
2390                theTail->event.data.mouse.eventNum =
2391                    leftENum = getUniqueEventNum();
2392                break;
2393            case NX_RMOUSEDOWN:
2394                theTail->event.data.mouse.eventNum =
2395                    rightENum = getUniqueEventNum();
2396                break;
2397            case NX_LMOUSEUP:
2398                theTail->event.data.mouse.eventNum = leftENum;
2399                leftENum = NULLEVENTNUM;
2400                // Inform the devices that the mouse was clicked
2401                notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage);
2402                break;
2403            case NX_RMOUSEUP:
2404                theTail->event.data.mouse.eventNum = rightENum;
2405                rightENum = NULLEVENTNUM;
2406                // Inform the devices that the mouse was clicked
2407                notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage);
2408                break;
2409        }
2410
2411        if (EventCodeMask(what) & PRESSUREEVENTMASK) {
2412            // this case will not happen unless someone modifies PRESSUREEVENTMASK
2413            if (!((EventCodeMask(what) & MOUSEEVENTMASK) || (EventCodeMask(what) & MOVEDEVENTMASK)))
2414                IOLog("%s: postEvent unknown pressure event, cannot fill pressure.\n", registryName);
2415        }
2416        if (EventCodeMask(what) & MOUSEEVENTMASK) {
2417            /* Click state */
2418            AbsoluteTime delta = ts;
2419            SUB_ABSOLUTETIME( &delta, &clickTime);
2420            if ((CMP_ABSOLUTETIME(&delta, &clickTimeThresh) <= 0)
2421                    && (myAbs(location->xValue().as64() - clickLoc.x) <= clickSpaceThresh.x)
2422                    && (myAbs(location->yValue().as64() - clickLoc.y) <= clickSpaceThresh.y)) {
2423                if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
2424                    clickTime = ts;
2425                    theTail->event.data.mouse.click = ++clickState;
2426                }
2427                else {
2428                    theTail->event.data.mouse.click = clickState;
2429                }
2430            }
2431            else if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
2432                clickLoc = *location;
2433                clickTime = ts;
2434                clickState = 1;
2435                theTail->event.data.mouse.click = clickState;
2436            }
2437            else
2438                theTail->event.data.mouse.click = 0;
2439        }
2440#if PMON
2441        pmon_log_event(PMON_SOURCE_EV,
2442                       KP_EV_POST_EVENT,
2443                       what,
2444                       evg->eventFlags,
2445                       theClock);
2446#endif
2447        evg->LLETail = theTail->next;
2448        evg->LLELast = theLast->next;
2449        if ( ! wereEvents ) // Events available, so wake event consumer
2450            kickEventConsumer();
2451    }
2452    else {
2453        /*
2454         * if queue is full, ignore event, too hard to take care of all cases
2455         */
2456        static uint64_t next_log = 0;
2457        if (AbsoluteTime_to_scalar(&ts) > next_log)
2458        {
2459            IOLog("%s: postEvent LLEventQueue overflow.\n", registryName);
2460            nanoseconds_to_absolutetime(60000000000LL, (AbsoluteTime*)&next_log);
2461            next_log += AbsoluteTime_to_scalar(&ts);
2462        }
2463        kickEventConsumer();
2464#if PMON
2465        pmon_log_event( PMON_SOURCE_EV,
2466                        KP_EV_QUEUE_FULL,
2467                        what,
2468                        evg->eventFlags,
2469                        theClock);
2470#endif
2471    }
2472    PROFILE_TRACE(8);
2473}
2474
2475/*
2476 * - kickEventConsumer
2477 *
2478 *  Try to send a message out to let the event consumer know that
2479 *  there are now events available for consumption.
2480 */
2481
2482void IOHIDSystem::kickEventConsumer()
2483{
2484    xpr_ev_post("kickEventConsumer (need == %d)\n",
2485        needToKickEventConsumer,2,3,4,5);
2486
2487    if ( needToKickEventConsumer == true )
2488        return;     // Request is already pending
2489
2490    needToKickEventConsumer = true; // Posting a request now
2491
2492        // Trigger eventConsumerES, so that doKickEventConsumer
2493        // is run from the workloop thread.
2494        eventConsumerES->interruptOccurred(0, 0, 0);
2495}
2496
2497/*
2498 * - sendStackShotMessage
2499 *
2500 *  Try to send a message out to let the stack shot know we got
2501 *  the magic key sequence
2502 */
2503
2504void IOHIDSystem::sendStackShotMessage(UInt32 flavor)
2505{
2506    kern_return_t r;
2507    mach_msg_header_t *msgh;
2508
2509    xpr_ev_post("sendStackShotMessage\n", 1,2,3,4,5);
2510
2511    if (stackShotMsg) {
2512        ((_stackShotMessage*)stackShotMsg)->flavor = flavor;
2513        msgh = (mach_msg_header_t *)stackShotMsg;
2514        if( msgh) {
2515
2516            r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
2517            switch ( r ) {
2518                case MACH_SEND_TIMED_OUT:/* Already has a message posted */
2519                case MACH_MSG_SUCCESS:  /* Message is posted */
2520                    break;
2521                default:        /* Log the error */
2522                    IOLog("%s: sendStackShotMessage msg_send returned %d\n", registryName, r);
2523                    break;
2524            }
2525        }
2526    }
2527}
2528
2529/*
2530 * HID System no longer runs the following methods on the EventSource thread.
2531 * Instead all are run from the caller thread through the use of command gates.
2532 * This will limit the amount of context switching that takes place.
2533 */
2534
2535
2536/*
2537 * The following methods are executed from the caller thread only.
2538 */
2539
2540/*
2541 * The method is now called from a command gate and is run on the caller thread
2542 */
2543
2544void IOHIDSystem::doSpecialKeyMsg(IOHIDSystem * self,
2545                    struct evioSpecialKeyMsg *msg) /* IOCommandGate::Action */
2546{
2547    kern_return_t r;
2548
2549    xpr_ev_post("doSpecialKeyMsg 0x%x\n", msg,2,3,4,5);
2550
2551
2552    /* FIXME: Don't block */
2553    r = mach_msg_send_from_kernel( &msg->Head, msg->Head.msgh_size);
2554
2555    xpr_ev_post("doSpecialKeyMsg: msg_send() == %d\n",r,2,3,4,5);
2556    if ( r != MACH_MSG_SUCCESS )
2557    {
2558        IOLog("%s: doSpecialKeyMsg msg_send returned %d\n",
2559            self->registryName, r);
2560    }
2561    if ( r == MACH_SEND_INVALID_DEST )  /* Invalidate the port */
2562    {
2563        self->setSpecialKeyPort(
2564          /* keyFlavor */ msg->key,
2565          /* keyPort   */ MACH_PORT_NULL);
2566    }
2567    IOFree( (void *)msg, sizeof (struct evioSpecialKeyMsg) );
2568}
2569
2570/*
2571 * This is now being run from the workloop via an IOInterruptEventSource.
2572 * Note that we perform a non-blocking send.  The Event port in the event
2573 * consumer has a queue depth of 1 message.  Once the consumer picks up that
2574 * message, it runs until the event queue is exhausted before trying to read
2575 * another message.  If a message is pending,there is no need to enqueue a
2576 * second one.  This also keeps us from blocking the I/O thread in a msg_send
2577 * which could result in a deadlock if the consumer were to make a call into
2578 * the event driver.
2579 */
2580void IOHIDSystem::doKickEventConsumer(IOHIDSystem * self)  /*IOInterruptEventSource::Action */
2581{
2582    kern_return_t r;
2583    mach_msg_header_t *msgh;
2584
2585    self->needToKickEventConsumer = false;   // Request received and processed
2586
2587        // RY: If the eventPost is null, do nothing
2588        if ( self->eventPort == MACH_PORT_NULL )
2589            return;
2590
2591    xpr_ev_post("doKickEventConsumer\n", 1,2,3,4,5);
2592
2593    msgh = (mach_msg_header_t *)self->eventMsg;
2594    if( msgh) {
2595
2596            r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
2597            switch ( r )
2598            {
2599                case MACH_SEND_TIMED_OUT:/* Already has a message posted */
2600                case MACH_MSG_SUCCESS:  /* Message is posted */
2601                    break;
2602                default:        /* Log the error */
2603                    IOLog("%s: doKickEventConsumer msg_send returned %d\n",
2604                self->registryName, r);
2605                    break;
2606            }
2607    }
2608}
2609
2610void IOHIDSystem::scheduleNextPeriodicEvent()
2611{
2612    if ( !eventsOpen ) {
2613        // If eventsOpen is false, then the driver shmem is
2614        // no longer valid, and it is in the process of shutting down.
2615        // We should give up without rescheduling.
2616        IOHID_DEBUG(kIOHIDDebugCode_Scheduling, 0, 0, 0, 0);
2617    }
2618    else {
2619        uint64_t soon; // 1 ms from now
2620        uint64_t scheduledEvent = _periodicEventNext;
2621
2622        clock_interval_to_deadline(1, kMillisecondScale, &soon);
2623
2624        if ((scheduledEvent > _periodicEventLast) && (scheduledEvent < soon)) {
2625            // we have an event scheduled "soon". Do not reschedule.
2626        }
2627        else {
2628            if (scheduledEvent <= _periodicEventLast) {
2629                // scheduledEvent is old. do not reuse.
2630                scheduledEvent = UINT64_MAX;
2631            }
2632
2633            if (screens && (kIOPMDeviceUsable | displayState)) {
2634                uint64_t nextMove = _cursorMoveLast + _cursorMoveDelta;
2635                uint64_t nextWait = _cursorWaitLast + _cursorWaitDelta;
2636
2637                if (_cursorMoveDelta) {
2638                    if (_cursorEventLast > _cursorMoveLast) {
2639                        scheduledEvent = nextMove;
2640                    }
2641                }
2642
2643                if (_cursorWaitDelta && evg->waitCursorEnabled && evg->globalWaitCursorEnabled) {
2644                    if (scheduledEvent > nextWait) {
2645                        scheduledEvent = nextWait;
2646                    }
2647                }
2648                IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, nextMove, nextWait, 0);
2649            }
2650            else {
2651                // We have something to do, but no one is "listening".
2652                // Try again in 30 ms.
2653                clock_interval_to_deadline(30, kMillisecondScale, &scheduledEvent);
2654                IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, 0, 0, 0);
2655            }
2656
2657            if (UINT64_MAX == scheduledEvent) {
2658                // no periodic events. cancel any pending periodic timer.
2659                periodicES->cancelTimeout();
2660            }
2661            else {
2662                _periodicEventNext = scheduledEvent;
2663                IOReturn err = periodicES->wakeAtTime(_periodicEventNext);
2664                if (err) {
2665                    IOLog("%s:%d wakeAtTime failed for %lld: %08x (%s)\n", __func__, __LINE__, _periodicEventNext, err, stringFromReturn(err));
2666                }
2667            }
2668        }
2669    }
2670}
2671
2672// Periodic events are driven from this method.
2673// After taking care of all pending work, the method
2674// calls scheduleNextPeriodicEvent to compute and set the
2675// next callout.
2676
2677// Modified this method to call a command Gate action.
2678// This will hopefully insure that this is serialized
2679// with other actions associated with the command gate.
2680
2681void IOHIDSystem::_periodicEvents(IOHIDSystem * self,
2682                                  IOTimerEventSource *timer)
2683{
2684    self->periodicEvents(timer);
2685}
2686
2687void IOHIDSystem::periodicEvents(IOTimerEventSource * timer __unused)
2688{
2689    // If eventsOpen is false, then the driver shmem is
2690    // no longer valid, and it is in the process of shutting down.
2691    // We should give up without rescheduling.
2692    if ( !eventsOpen )
2693        return;
2694
2695    clock_get_uptime(&_periodicEventLast);  // update last event
2696    _periodicEventNext = UINT64_MAX;        // currently no next event
2697
2698    // Update cursor position if needed
2699    if (_periodicEventLast >= _cursorMoveLast + _cursorMoveDelta) {
2700        _cursorHelper.startPosting();
2701        _cursorHelper.applyPostingDelta();
2702        _setCursorPosition(false, false, lastSender);
2703        OSSafeReleaseNULL(lastSender);
2704        _cursorMoveLast = _periodicEventLast;
2705    }
2706
2707    // WAITCURSOR ACTION
2708    if ( OSSpinLockTry(&evg->waitCursorSema) )
2709    {
2710        if ( OSSpinLockTry(&evg->cursorSema) )
2711        {
2712            // If wait cursor enabled and context timed out, do waitcursor
2713            if (evg->waitCursorEnabled && evg->globalWaitCursorEnabled)
2714            {
2715                /* WAIT CURSOR SHOULD BE ON */
2716                if (!evg->waitCursorUp) {
2717                    showWaitCursor();
2718                    _cursorWaitLast = _periodicEventLast;
2719                }
2720            }
2721            else {
2722                /* WAIT CURSOR SHOULD BE OFF */
2723                if (evg->waitCursorUp && ((_cursorWaitLast + _cursorWaitDelta) < _periodicEventLast)) {
2724                    hideWaitCursor();
2725                    _cursorWaitLast = _periodicEventLast;
2726                }
2727            }
2728            /* Animate cursor */
2729            if (evg->waitCursorUp && ((_cursorWaitLast + _cursorWaitDelta) < _periodicEventLast)) {
2730                animateWaitCursor();
2731                _cursorWaitLast = _periodicEventLast;
2732            }
2733            OSSpinLockUnlock(&evg->cursorSema);
2734        }
2735        OSSpinLockUnlock(&evg->waitCursorSema);
2736    }
2737
2738    scheduleNextPeriodicEvent();
2739
2740    return;
2741}
2742
2743//
2744// Start the cursor system running.
2745//
2746// At this point, the WindowServer is up, running, and ready to process events.
2747// We will attach the keyboard and mouse, if none are available yet.
2748//
2749bool IOHIDSystem::resetCursor()
2750{
2751    volatile IOGPoint * p;
2752    UInt32 newScreens = 0;
2753    SInt32 candidate = 0;
2754    SInt32 pinScreen = -1L;
2755
2756    p = &evg->cursorLoc;
2757
2758    /* Get mask of screens on which the cursor is present */
2759    EvScreen *screen = (EvScreen *)evScreen;
2760    for (int i = 0; i < screens; i++ ) {
2761        if (!screen[i].desktopBounds)
2762            continue;
2763        if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
2764            continue;
2765        candidate = i;
2766        if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
2767            pinScreen = i;
2768            newScreens |= (1 << i);
2769        }
2770    }
2771
2772    if (newScreens == 0)
2773        pinScreen = candidate;
2774
2775    if (!cursorPinned) {
2776        // reset pin rect
2777        if (((EvScreen*)evScreen)[pinScreen].desktopBounds) {
2778            cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds);
2779            cursorPin.maxx--;   /* Make half-open rectangle */
2780            cursorPin.maxy--;
2781            cursorPinScreen = pinScreen;
2782        }
2783        else {
2784            // How do you pin when there are no screens with bounds...
2785        }
2786    }
2787
2788    if (newScreens == 0) {
2789        /* Pin new cursor position to cursorPin rect */
2790        p->x = (p->x < cursorPin.minx) ?
2791            cursorPin.minx : ((p->x > cursorPin.maxx) ?
2792            cursorPin.maxx : p->x);
2793        p->y = (p->y < cursorPin.miny) ?
2794            cursorPin.miny : ((p->y > cursorPin.maxy) ?
2795            cursorPin.maxy : p->y);
2796
2797        /* regenerate mask for new position */
2798        for (int i = 0; i < screens; i++ ) {
2799            if (!screen[i].desktopBounds)
2800                continue;
2801            if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
2802                continue;
2803            if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)){
2804                pinScreen = i;
2805                newScreens |= (1 << i);
2806            }
2807        }
2808    }
2809
2810    cursorScreens = newScreens;
2811    IOFixedPoint64 tempLoc;
2812    if (evg->updateCursorPositionFromFixed) {
2813        tempLoc.fromFixed24x8(evg->desktopCursorFixed.x, evg->desktopCursorFixed.y);
2814    }
2815    else {
2816        tempLoc.fromIntFloor(evg->cursorLoc.x, evg->cursorLoc.y);
2817    }
2818    _cursorHelper.desktopLocationDelta() += tempLoc - _cursorHelper.desktopLocation();
2819    _cursorHelper.desktopLocation() = tempLoc;
2820    if (pinScreen >= 0) {
2821        _cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds);
2822    }
2823    else {
2824        _cursorHelper.updateScreenLocation(NULL, NULL);
2825    }
2826
2827    _cursorMoveDelta = _cursorWaitDelta = 0;
2828    _cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
2829    _cursorHelper.clearEventCounts();
2830
2831    _cursorLogTimed();
2832
2833    scheduleNextPeriodicEvent();
2834
2835    return( true );
2836}
2837
2838bool IOHIDSystem::startCursor()
2839{
2840    if (0 == screens) {
2841        // no screens, no cursor
2842    }
2843    else {
2844        cursorPinned = false;
2845        resetCursor();
2846        showCursor();
2847
2848        // Start the cursor control callouts
2849        scheduleNextPeriodicEvent();
2850
2851        cursorStarted = true;
2852    }
2853
2854    return( cursorStarted );
2855}
2856
2857//
2858// Wait Cursor machinery.  These methods should be run from a command
2859// gate action and the shared memory area must be set up.
2860//
2861void IOHIDSystem::showWaitCursor()
2862{
2863    xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5);
2864    evg->waitCursorUp = true;
2865    hideCursor();
2866    evg->frame = EV_WAITCURSOR;
2867    showCursor();
2868}
2869
2870void IOHIDSystem::hideWaitCursor()
2871{
2872    xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5);
2873    evg->waitCursorUp = false;
2874    hideCursor();
2875    evg->frame = EV_STD_CURSOR;
2876    showCursor();
2877}
2878
2879void IOHIDSystem::animateWaitCursor()
2880{
2881    xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5);
2882    changeCursor(evg->frame + 1);
2883}
2884
2885void IOHIDSystem::changeCursor(int frame)
2886{
2887    evg->frame = ((frame > (int)maxWaitCursorFrame) || (frame > evg->lastFrame)) ? firstWaitCursorFrame : frame;
2888    xpr_ev_cursor("changeCursor %d\n",evg->frame,2,3,4,5);
2889    moveCursor();
2890}
2891
2892//
2893// Return the screen number in which point p lies.  Return -1 if the point
2894// lies outside of all registered screens.
2895//
2896int IOHIDSystem::pointToScreen(IOGPoint * p)
2897{
2898    int i;
2899    EvScreen *screen = (EvScreen *)evScreen;
2900    for (i=screens; --i != -1; ) {
2901        if ((screen[i].desktopBounds != 0)
2902            && (p->x >= screen[i].desktopBounds->minx)
2903            && (p->x < screen[i].desktopBounds->maxx)
2904            && (p->y >= screen[i].desktopBounds->miny)
2905            && (p->y < screen[i].desktopBounds->maxy))
2906        return i;
2907    }
2908    return(-1); /* Cursor outside of known screen boundary */
2909}
2910
2911//
2912// API used to drive event state out to attached screens
2913//
2914// These should be run from a command gate action.
2915//
2916inline void IOHIDSystem::showCursor()
2917{
2918    evDispatch(/* command */ EVSHOW);
2919}
2920inline void IOHIDSystem::hideCursor()
2921{
2922    evDispatch(/* command */ EVHIDE);
2923}
2924
2925inline void IOHIDSystem::moveCursor()
2926{
2927    evDispatch(/* command */ EVMOVE);
2928}
2929
2930//
2931// - attachDefaultEventSources
2932//  Attach the default event sources.
2933//
2934void IOHIDSystem::attachDefaultEventSources()
2935{
2936    IOService  *     source;
2937    OSIterator *    sources;
2938
2939
2940        sources = getProviderIterator();
2941
2942        if (!sources)  return;
2943
2944    while( (source = (IOService *)sources->getNextObject())) {
2945        if ((OSDynamicCast(IOHIDevice, source) && !OSDynamicCast(IOHIKeyboard, source))
2946            || OSDynamicCast(IOHIDEventService, source)) {
2947
2948            registerEventSource(source);
2949       }
2950    }
2951        sources->release();
2952}
2953
2954//
2955// - detachEventSources
2956//  Detach all event sources
2957//
2958void IOHIDSystem::detachEventSources()
2959{
2960    OSIterator * iter;
2961    IOService * srcInstance;
2962
2963    iter = getOpenProviderIterator();
2964    if( iter) {
2965        while( (srcInstance = (IOService *) iter->getNextObject())) {
2966
2967            if ( ! OSDynamicCast(IOHIKeyboard, srcInstance) ) {
2968                #ifdef DEBUG
2969                kprintf("detachEventSource:%s\n", srcInstance->getName());
2970                #endif
2971                srcInstance->close(this);
2972            }
2973        }
2974        iter->release();
2975    }
2976}
2977
2978//
2979// EventSrcClient implementation
2980//
2981
2982//
2983// A new device instance desires to be added to our list.
2984// Try to get ownership of the device. If we get it, add it to
2985// the list.
2986//
2987bool IOHIDSystem::registerEventSource(IOService * source)
2988{
2989    bool success = false;
2990
2991#ifdef DEBUG
2992    kprintf("registerEventSource:%s\n", source->getName());
2993#endif
2994
2995    if ( OSDynamicCast(IOHIKeyboard, source) ) {
2996        success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,0,
2997                    (KeyboardEventCallback)        _keyboardEvent,
2998                    (KeyboardSpecialEventCallback) _keyboardSpecialEvent,
2999                    (UpdateEventFlagsCallback)     _updateEventFlags);
3000        source->setProperty(kIOHIDResetKeyboardKey, kOSBooleanTrue);
3001    } else if ( OSDynamicCast(IOHIPointing, source) ) {
3002        if ( OSDynamicCast(IOHITablet, source) ) {
3003            success = ((IOHITablet*)source)->open(this, kIOServiceSeize,0,
3004                        (RelativePointerEventCallback)  _relativePointerEvent,
3005                        (AbsolutePointerEventCallback)  _absolutePointerEvent,
3006                        (ScrollWheelEventCallback)      _scrollWheelEvent,
3007                        (TabletEventCallback)           _tabletEvent,
3008                        (ProximityEventCallback)        _proximityEvent);
3009        } else {
3010            success = ((IOHIPointing*)source)->open(this, kIOServiceSeize,0,
3011                        (RelativePointerEventCallback) _relativePointerEvent,
3012                        (AbsolutePointerEventCallback) _absolutePointerEvent,
3013                        (ScrollWheelEventCallback)     _scrollWheelEvent);
3014        }
3015        source->setProperty(kIOHIDResetPointerKey, kOSBooleanTrue);
3016    } else {
3017        success = source->open(this, kIOServiceSeize, 0);
3018    }
3019
3020    if ( success )
3021    {
3022
3023        OSDictionary * newParams = OSDictionary::withDictionary( savedParameters );
3024        if( newParams) {
3025
3026            // update with user settings
3027            if ( OSDynamicCast(IOHIDevice, source) )
3028                ((IOHIDevice *)source)->setParamProperties( newParams );
3029            else if ( OSDynamicCast(IOHIDEventService, source) )
3030                ((IOHIDEventService *)source)->setSystemProperties( newParams );
3031
3032            setProperty( kIOHIDParametersKey, newParams );
3033            newParams->release();
3034            savedParameters = newParams;
3035        }
3036
3037    }
3038    else
3039        IOLog("%s: Seize of %s failed.\n", registryName, source->getName());
3040
3041    return success;
3042}
3043
3044IOReturn IOHIDSystem::message(UInt32 type, IOService * provider,
3045                void * argument)
3046{
3047    IOReturn     status = kIOReturnSuccess;
3048
3049    switch (type)
3050    {
3051        case kIOMessageServiceIsTerminated:
3052            provider->close( this );
3053        case kIOMessageServiceWasClosed:
3054            break;
3055
3056        case kIOHIDSystemActivityTickle: {
3057            intptr_t nxEvent = (intptr_t) argument;
3058            if ((nxEvent >= 0) && (nxEvent <= NX_LASTEVENT)) {
3059                if (!evStateChanging && displayManager) {
3060                    IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState,
3061                                provider ? provider->getRegistryEntryID() : 0);
3062                    if (DISPLAY_IS_ENABLED || (NX_WAKEMASK & EventCodeMask(nxEvent))) {
3063                        if (!DISPLAY_IS_ENABLED) {
3064                            kprintf("IOHIDSystem tickle when screen off for event %ld\n", nxEvent);
3065                        }
3066                        displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent));
3067                    }
3068                }
3069            }
3070            else if (nxEvent == NX_HARDWARE_TICKLE) {
3071                if (!evStateChanging && displayManager) {
3072                    IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState,
3073                                provider ? provider->getRegistryEntryID() : 0);
3074                    if (!DISPLAY_IS_ENABLED) {
3075                        kprintf("IOHIDSystem tickle when screen off for hardware event from %08llx\n",
3076                                provider ? provider->getRegistryEntryID() : 0);
3077                    }
3078                    displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent));
3079                }
3080            }
3081            else {
3082                IOLog("kIOHIDSystemActivityTickle message for unsupported event %ld sent from %08llx\n",
3083                      nxEvent, provider ? provider->getRegistryEntryID() : 0);
3084            }
3085            break;
3086        }
3087
3088        default:
3089            status = super::message(type, provider, argument);
3090            break;
3091    }
3092
3093    return status;
3094}
3095
3096//
3097// This will scale the point at location in the coordinate system represented by bounds
3098// to the coordinate system of the current screen.
3099// This is needed for absolute pointer events that come from devices with different bounds.
3100//
3101void IOHIDSystem::scaleLocationToCurrentScreen(IOGPoint *location, IOGBounds *bounds __unused)
3102{
3103    IOHIDSystem * hidsystem = instance();
3104
3105    if ( hidsystem ) {
3106        IOFixedPoint64 temp;
3107        temp.fromIntFloor(location->x, location->y);
3108        hidsystem->_scaleLocationToCurrentScreen(temp, bounds);
3109        *location = (IOGPoint)temp;
3110    }
3111}
3112
3113void IOHIDSystem::_scaleLocationToCurrentScreen(IOFixedPoint64 &location, IOGBounds *bounds)
3114{
3115    if (!bounds) {
3116        // no transform can be performed
3117    }
3118    else {
3119        if (*(UInt64*)&cursorPin == *(UInt64*)bounds) {
3120            //  no transform needed
3121        }
3122        else {
3123            int boundsWidth   = bounds->maxx  - bounds->minx;
3124            int boundsHeight  = bounds->maxy  - bounds->miny;
3125            int cursorPinWidth  = cursorPin.maxx - cursorPin.minx;
3126            int cursorPinHeight = cursorPin.maxy - cursorPin.miny;
3127            if ((boundsWidth <= 0) || (boundsHeight <= 0) || (cursorPinWidth <= 0) || (cursorPinHeight <= 0)) {
3128                // no transform can be performed
3129            }
3130            else {
3131                IOFixedPoint64 scratch;
3132                if ((boundsWidth == cursorPinWidth) && (boundsHeight == cursorPinHeight)) {
3133                    // translation only
3134                    location += scratch.fromIntFloor(bounds->minx - cursorPin.minx,
3135                                                     bounds->miny - cursorPin.miny);
3136                }
3137                else {
3138                    // full transform
3139                    IOFixed64 x_scale;
3140                    IOFixed64 y_scale;
3141                    x_scale.fromIntFloor(cursorPinWidth) /= boundsWidth;
3142                    y_scale.fromIntFloor(cursorPinHeight) /= boundsHeight;
3143                    location -= scratch.fromIntFloor(bounds->minx, bounds->miny);
3144                    location *= scratch.fromFixed64(x_scale, y_scale);
3145                    location += scratch.fromIntFloor(cursorPin.minx, cursorPin.miny);
3146                }
3147            }
3148        }
3149    }
3150    return;
3151}
3152
3153//
3154// Process a mouse status change.  The driver should sign extend
3155// it's deltas and perform any bit flipping needed there.
3156//
3157// We take the state as presented and turn it into events.
3158//
3159void IOHIDSystem::_relativePointerEvent(IOHIDSystem * self,
3160                    int        buttons,
3161                       /* deltaX */ int        dx,
3162                       /* deltaY */ int        dy,
3163                       /* atTime */ AbsoluteTime ts,
3164                                    OSObject * sender,
3165                                    void *     refcon __unused)
3166{
3167    self->relativePointerEvent(buttons, dx, dy, ts, sender);
3168}
3169
3170void IOHIDSystem::relativePointerEvent(int        buttons,
3171                          /* deltaX */ int        dx,
3172                          /* deltaY */ int        dy,
3173                          /* atTime */ AbsoluteTime ts)
3174{
3175    relativePointerEvent(buttons, dx, dy, ts, 0);
3176}
3177
3178void IOHIDSystem::relativePointerEvent(int        buttons,
3179                          /* deltaX */   int        dx,
3180                          /* deltaY */   int        dy,
3181                          /* atTime */   AbsoluteTime ts,
3182                          /* sender */   OSObject * sender)
3183{
3184    IOHIDCmdGateActionArgs args;
3185    args.arg0 = &buttons;
3186    args.arg1 = &dx;
3187    args.arg2 = &dy;
3188    args.arg3 = &ts;
3189    args.arg4 = sender;
3190
3191    cmdGate->runAction((IOCommandGate::Action)doRelativePointerEvent, &args);
3192}
3193
3194
3195IOReturn IOHIDSystem::doRelativePointerEvent(IOHIDSystem *self, void * args)
3196                        /* IOCommandGate::Action */
3197{
3198    int             buttons = *(int *)((IOHIDCmdGateActionArgs *)args)->arg0;
3199    int             dx  = *(int *)((IOHIDCmdGateActionArgs *)args)->arg1;
3200    int             dy  = *(int *)((IOHIDCmdGateActionArgs *)args)->arg2;
3201    SInt64          ts  = *(SInt64 *)((IOHIDCmdGateActionArgs *)args)->arg3;
3202    OSObject *          sender  = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg4;
3203
3204    self->relativePointerEventGated(buttons, dx, dy, ts, sender);
3205
3206    return kIOReturnSuccess;
3207}
3208
3209//************************************************************
3210static bool vblForScreen(IOGraphicsDevice *io_gd_I, uint64_t &delta_O)
3211{
3212    uint64_t        nextVBL = 0;
3213    static UInt64   minVBLdelta = 0;
3214    static UInt64   maxVBLdelta = 0;
3215
3216    // rdar://5565815 Capping VBL interval
3217    if (!minVBLdelta) {
3218        // A screen refresh of more than 50ms (20Hz) is not acceptable.
3219        nanoseconds_to_absolutetime(50000000, (&maxVBLdelta));
3220        // A screen refresh of less than 5ms (200Hz) is not necessary.
3221        nanoseconds_to_absolutetime(5000000, (&minVBLdelta));
3222    }
3223
3224    if (io_gd_I) {
3225        io_gd_I->getVBLTime( &nextVBL, &delta_O );
3226        if (delta_O < minVBLdelta) {
3227            delta_O = minVBLdelta;
3228        }
3229        else if (delta_O > maxVBLdelta) {
3230            delta_O = maxVBLdelta;
3231        }
3232    }
3233    else {
3234        delta_O = maxVBLdelta;
3235    }
3236
3237    return (nextVBL != 0);
3238}
3239
3240void IOHIDSystem::relativePointerEventGated(int buttons, int dx_I, int dy_I, SInt64 ts, OSObject * sender)
3241{
3242    bool movementEvent = false;
3243
3244    PROFILE_TRACE(1);
3245
3246    if( eventsOpen == false )
3247        return;
3248
3249    // Compare relative mouse deltas against thresholds to determine if the
3250    // movement should generate a tickle. This will prevent chatty mice from
3251    // tickling without user input.
3252    CachedMouseEventStruct *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
3253    if (cachedMouseEvent) {
3254        UInt64 ts_nano;
3255        absolutetime_to_nanoseconds(ts, &ts_nano);
3256
3257        if (ts_nano > cachedMouseEvent->eventDeadline) {
3258            cachedMouseEvent->eventDeadline = ts_nano + kIOHIDChattyMouseSuppressionDelayNS;
3259            cachedMouseEvent->accumX = 0;
3260            cachedMouseEvent->accumY = 0;
3261        }
3262
3263        cachedMouseEvent->accumX += dx_I;
3264        cachedMouseEvent->accumY += dy_I;
3265
3266        if ((abs(cachedMouseEvent->accumX) >= kIOHIDRelativeTickleThresholdPixel) ||
3267            (abs(cachedMouseEvent->accumY) >= kIOHIDRelativeTickleThresholdPixel))
3268        {
3269            movementEvent = true;
3270        }
3271
3272        cachedMouseEvent->lastButtons = buttons;
3273        cachedMouseEvent->eventDeadline = ts_nano;
3274
3275        // Fake up pressure changes from button state changes
3276        if( (buttons & EV_LB) != (evg->buttons & EV_LB) ){
3277            cachedMouseEvent->lastPressure = ( buttons & EV_LB ) ? MAXPRESSURE : MINPRESSURE;
3278        }
3279    }
3280
3281    // do not tickle on movement if the screen is dark (some restrictions apply)
3282    if      (buttons & EV_LB) {
3283        // always tickle on left button down
3284        TICKLE_DISPLAY(NX_LMOUSEDOWN);
3285    }
3286    else if (buttons & EV_RB) {
3287        // always tickle on right button down
3288        TICKLE_DISPLAY(NX_RMOUSEDOWN);
3289    }
3290    else if (buttons) {
3291        // always tickle on other buttons down
3292        TICKLE_DISPLAY(NX_OMOUSEDOWN);
3293    }
3294    else if (movementEvent) {
3295        if (DISPLAY_IS_ENABLED) {
3296            // the display is on. send a moved tickle.
3297            TICKLE_DISPLAY(NX_MOUSEMOVED);
3298        }
3299        else
3300        {
3301            // the display is off...
3302            if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0) {
3303                // but not too much time has passed. send a moved tickle.
3304                TICKLE_DISPLAY(NX_MOUSEMOVED);
3305            }
3306            return;
3307        }
3308    }
3309
3310    if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
3311        return;
3312    }
3313
3314    _setButtonState(buttons, /* atTime */ ts, sender);
3315
3316    _cursorHelper.incrementEventCount();
3317    IOFixedPoint64 scratch;
3318    if ( scratch.fromIntFloor(dx_I, dy_I) ) {
3319        UInt64              uptime = 0;
3320        bool                haveVBL = vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta);
3321
3322        clock_get_uptime(&uptime);
3323
3324        if (((scratch.xValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() < 0LL)) ||
3325            ((scratch.xValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() > 0LL))) {
3326            _cursorHelper.desktopLocationAccumulated().xValue().fromIntFloor(0);
3327        }
3328        if (((scratch.yValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() < 0LL)) ||
3329            ((scratch.yValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() > 0LL))) {
3330            _cursorHelper.desktopLocationAccumulated().yValue().fromIntFloor(0);
3331        }
3332
3333        IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventTiming, _cursorMoveDelta, 0,
3334                    dx_I, dy_I);
3335
3336        _cursorHelper.desktopLocationAccumulated() += scratch;
3337
3338        scratch = _cursorHelper.desktopLocationAccumulated(); // for ease of reference
3339        _cursorEventLast = uptime;
3340
3341        if (!haveVBL) {
3342            // no VBL
3343            // post immediatly
3344            periodicEvents(NULL);
3345        }
3346        else {
3347            // see rdar://7675662
3348            if (cachedMouseEvent && (cachedMouseEvent->reportInterval_ns > 0)) {
3349                uint64_t cursorMoveDelta_ns;
3350                absolutetime_to_nanoseconds(_cursorMoveDelta, &cursorMoveDelta_ns);
3351                _cursorHelper.expectedCount().fromIntFloor(cursorMoveDelta_ns);
3352                _cursorHelper.expectedCount() /= cachedMouseEvent->reportInterval_ns;
3353                IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventScaling,
3354                            scratch.xValue().asFixed(), scratch.yValue().asFixed(),
3355                            _cursorHelper.expectedCount().asFixed(),
3356                            _cursorHelper.getEventCountPosting() * 65536);
3357            }
3358            else {
3359                _cursorHelper.expectedCount().fromIntFloor(0);
3360            }
3361
3362            if (sender)
3363                sender->retain();
3364            OSSafeReleaseNULL(lastSender);
3365            lastSender = sender;
3366
3367            if (uptime > _cursorMoveLast + 2 * _cursorMoveDelta) {
3368                // either we are not posting currently or this event is overdue.
3369                // post immediately
3370                periodicEvents(periodicES); // handles scheduling
3371            }
3372            else {
3373                scheduleNextPeriodicEvent();
3374            }
3375        }
3376        _cursorLog(AbsoluteTime_to_scalar(&ts));
3377    }
3378    PROFILE_TRACE(2);
3379}
3380
3381void IOHIDSystem::_absolutePointerEvent(
3382                                IOHIDSystem *   self,
3383                                int             buttons,
3384            /* at */            IOGPoint *      newLoc,
3385            /* withBounds */    IOGBounds *     bounds,
3386            /* inProximity */   bool            proximity,
3387            /* withPressure */  int             pressure,
3388            /* withAngle */     int             stylusAngle,
3389            /* atTime */        AbsoluteTime    ts,
3390                                OSObject *      sender,
3391                                void *          refcon __unused)
3392{
3393    self->absolutePointerEvent(buttons, newLoc, bounds, proximity,
3394                    pressure, stylusAngle, ts, sender);
3395}
3396
3397void IOHIDSystem::absolutePointerEvent(
3398                                int             buttons,
3399            /* at */            IOGPoint *      newLoc,
3400            /* withBounds */    IOGBounds *     bounds,
3401            /* inProximity */   bool            proximity,
3402            /* withPressure */  int             pressure,
3403            /* withAngle */     int             stylusAngle,
3404            /* atTime */        AbsoluteTime    ts)
3405{
3406    absolutePointerEvent(buttons, newLoc, bounds, proximity,
3407                    pressure, stylusAngle, ts, 0);
3408}
3409
3410void IOHIDSystem::absolutePointerEvent(
3411                                int             buttons,
3412            /* at */            IOGPoint *      newLoc,
3413            /* withBounds */    IOGBounds *     bounds,
3414            /* inProximity */   bool            proximity,
3415            /* withPressure */  int             pressure,
3416            /* withAngle */     int             stylusAngle,
3417            /* atTime */        AbsoluteTime    ts,
3418            /* sender */        OSObject *      sender)
3419{
3420    IOHIDCmdGateActionArgs args;
3421
3422    args.arg0 = &buttons;
3423    args.arg1 = (void *)newLoc;
3424    args.arg2 = (void *)bounds;
3425    args.arg3 = &proximity;
3426    args.arg4 = &pressure;
3427    args.arg5 = &stylusAngle;
3428    args.arg6 = &ts;
3429    args.arg7 = sender;
3430
3431    cmdGate->runAction((IOCommandGate::Action)doAbsolutePointerEvent, &args);
3432}
3433
3434IOReturn IOHIDSystem::doAbsolutePointerEvent(IOHIDSystem *self, void * args)
3435                        /* IOCommandGate::Action */
3436{
3437    int         buttons     = *(int *)  ((IOHIDCmdGateActionArgs *)args)->arg0;
3438    IOGPoint *  newLoc      = (IOGPoint *)  ((IOHIDCmdGateActionArgs *)args)->arg1;
3439    IOGBounds * bounds      = (IOGBounds *) ((IOHIDCmdGateActionArgs *)args)->arg2;
3440    bool        proximity   = *(bool *) ((IOHIDCmdGateActionArgs *)args)->arg3;
3441    int         pressure    = *(int *)  ((IOHIDCmdGateActionArgs *)args)->arg4;
3442    int         stylusAngle = *(int *)  ((IOHIDCmdGateActionArgs *)args)->arg5;
3443    AbsoluteTime    ts  = *(AbsoluteTime *)     ((IOHIDCmdGateActionArgs *)args)->arg6;
3444    OSObject *  sender          = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg7;
3445
3446
3447    self->absolutePointerEventGated(buttons, newLoc, bounds, proximity, pressure, stylusAngle, ts, sender);
3448
3449    return kIOReturnSuccess;
3450}
3451
3452void IOHIDSystem::absolutePointerEventGated(
3453                                int             buttons,
3454            /* at */            IOGPoint *      newLocGPoint,
3455            /* withBounds */    IOGBounds *     bounds __unused,
3456            /* inProximity */   bool            proximity,
3457            /* withPressure */  int             pressure,
3458            /* withAngle */     int             stylusAngle __unused,
3459            /* atTime */        AbsoluteTime    ts,
3460            /* sender */        OSObject *      sender)
3461{
3462
3463    /*
3464     * If you don't know what to pass for the following fields, pass the
3465     * default values below:
3466     *    pressure    = MINPRESSURE or MAXPRESSURE
3467     *    stylusAngle = 90
3468     */
3469    NXEventData     outData;    /* dummy data */
3470    bool            proximityChange = false;
3471
3472    PROFILE_TRACE(5);
3473
3474    if ( !eventsOpen )
3475        return;
3476
3477    if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
3478        TICKLE_DISPLAY(NX_MOUSEMOVED);
3479        return;
3480    }
3481
3482    if (!DISPLAY_IS_ENABLED) {
3483#if !WAKE_DISPLAY_ON_MOVEMENT
3484        if ( CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0 )
3485        {
3486            TICKLE_DISPLAY(NX_MOUSEMOVED);
3487            return;
3488        }
3489
3490        if (buttons)
3491#endif
3492        {
3493            TICKLE_DISPLAY(NX_LMOUSEDOWN);
3494        }
3495        return;
3496    }
3497
3498    TICKLE_DISPLAY(NX_MOUSEMOVED);
3499
3500    IOFixedPoint64 newLoc;
3501    newLoc.fromIntFloor(newLocGPoint->x, newLocGPoint->y);
3502    _scaleLocationToCurrentScreen(newLoc, bounds);
3503
3504    // RY: Attempt to add basic tablet support to absolute pointing devices
3505    // Basically, we will fill in the tablet support portions of both the
3506    // mouse and mouseMove of NXEventData.  Pending tablet events are stored
3507    // in the CachedMouseEventStruct and then later picked off in
3508    // _setButtonState and _postMouseMoveEvent
3509    CachedMouseEventStruct  *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
3510    if (cachedMouseEvent)
3511    {
3512        cachedMouseEvent->pointerFractionX = newLoc.xValue().fraction();
3513        cachedMouseEvent->pointerFractionY = newLoc.yValue().fraction();
3514
3515        proximityChange = (cachedMouseEvent->proximity != proximity);
3516
3517        cachedMouseEvent->state        |= kCachedMousePointingEventDispFlag;
3518        cachedMouseEvent->proximity     = proximity;
3519        cachedMouseEvent->lastPressure  = ScalePressure(pressure);
3520
3521        if ( !(cachedMouseEvent->state & kCachedMouseTabletEventDispFlag) )
3522        {
3523            // initialize the proximity and tablet event structs
3524            if ( !(cachedMouseEvent->state & kCachedMousePointingTabletEventDispFlag) )
3525            {
3526                cachedMouseEvent->state |= kCachedMousePointingTabletEventDispFlag;
3527                cachedMouseEvent->proximityData.proximity.capabilityMask  = (
3528                                                                             NX_TABLET_CAPABILITY_DEVICEIDMASK  |
3529                                                                             NX_TABLET_CAPABILITY_ABSXMASK |
3530                                                                             NX_TABLET_CAPABILITY_ABSYMASK |
3531                                                                             NX_TABLET_CAPABILITY_BUTTONSMASK |
3532                                                                             NX_TABLET_CAPABILITY_PRESSUREMASK);
3533                cachedMouseEvent->proximityData.proximity.pointerType       = NX_TABLET_POINTER_PEN;
3534                cachedMouseEvent->proximityData.proximity.systemTabletID    = IOHITablet::generateTabletID();
3535                cachedMouseEvent->proximityData.proximity.deviceID          =
3536                cachedMouseEvent->tabletData.tablet.deviceID                = IOHIDPointing::generateDeviceID();
3537            }
3538
3539            if ( proximityChange )
3540            {
3541                cachedMouseEvent->proximityData.proximity.enterProximity    = proximity;
3542                cachedMouseEvent->subType                                   = NX_SUBTYPE_TABLET_PROXIMITY;
3543
3544                cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag;
3545                proximityEventGated(&(cachedMouseEvent->proximityData), ts, sender);
3546                cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag;
3547            }
3548            else if ( proximity )
3549            {
3550                // RY: revert the button state
3551                // The window server requires that the lower 3 bits of
3552                // the buttons bit field be mangled for interpretation
3553                // when handling a button event.  Unfortunately,
3554                // applications that make use of the tablet events
3555                // require that the buttons field not be mangled.  Thus
3556                // the button state should be reverted.
3557                cachedMouseEvent->tabletData.tablet.buttons     = buttons & ~0x7;
3558                if (buttons & 2)
3559                    cachedMouseEvent->tabletData.tablet.buttons |= 4;
3560                if (buttons & EV_RB)
3561                    cachedMouseEvent->tabletData.tablet.buttons |= 2;
3562                if (buttons & EV_LB)
3563                    cachedMouseEvent->tabletData.tablet.buttons |= 1;
3564
3565                cachedMouseEvent->tabletData.tablet.x           = newLoc.xValue().as32();
3566                cachedMouseEvent->tabletData.tablet.y           = newLoc.yValue().as32();
3567                cachedMouseEvent->tabletData.tablet.pressure    = pressure;
3568                cachedMouseEvent->subType                       = NX_SUBTYPE_TABLET_POINT;
3569            }
3570        }
3571    }
3572
3573    clock_get_uptime(&_cursorEventLast);
3574    if ( (newLoc != _cursorHelper.desktopLocation()) || proximityChange)
3575    {
3576        _cursorHelper.desktopLocationDelta() = newLoc - _cursorHelper.desktopLocation();
3577        _cursorHelper.desktopLocation() = newLoc;
3578        _cursorLog(_cursorEventLast);
3579
3580        _setCursorPosition(false, proximityChange, sender);
3581        vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta);
3582        _cursorMoveLast = _cursorEventLast;
3583    }
3584
3585    if ( proximityChange && proximity == true )
3586    {
3587        evg->eventFlags |= NX_STYLUSPROXIMITYMASK;
3588        bzero( (char *)&outData, sizeof outData );
3589        postEvent(         NX_FLAGSCHANGED,
3590                  /* at */        &_cursorHelper.desktopLocation(),
3591                  /* atTime */   ts,
3592                  /* withData */ &outData,
3593                  /* sender */   sender);
3594    }
3595    if ( proximityChange || proximity == true )
3596        _setButtonState(buttons, /* atTime */ ts, sender);
3597    if ( proximityChange && proximity == false )
3598    {
3599        evg->eventFlags &= ~NX_STYLUSPROXIMITYMASK;
3600        bzero( (char *)&outData, sizeof outData );
3601        postEvent(         NX_FLAGSCHANGED,
3602                  /* at */       &_cursorHelper.desktopLocation(),
3603                  /* atTime */   ts,
3604                  /* withData */ &outData,
3605                  /* sender */   sender);
3606    }
3607
3608    // RY: Clean it off
3609    if (cachedMouseEvent)
3610    {
3611        cachedMouseEvent->subType = NX_SUBTYPE_DEFAULT;
3612        cachedMouseEvent->pointerFractionX = cachedMouseEvent->pointerFractionY = 0;
3613    }
3614
3615    scheduleNextPeriodicEvent();
3616    PROFILE_TRACE(6);
3617}
3618
3619void IOHIDSystem::_scrollWheelEvent(IOHIDSystem * self,
3620                                    short   deltaAxis1,
3621                                    short   deltaAxis2,
3622                                    short   deltaAxis3,
3623                                    IOFixed fixedDelta1,
3624                                    IOFixed fixedDelta2,
3625                                    IOFixed fixedDelta3,
3626                                    SInt32  pointDeltaAxis1,
3627                                    SInt32  pointDeltaAxis2,
3628                                    SInt32  pointDeltaAxis3,
3629                                    UInt32  options,
3630                 /* atTime */       AbsoluteTime ts,
3631                                    OSObject * sender,
3632                                    void *     refcon __unused)
3633{
3634        self->scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3,  pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender);
3635}
3636
3637void IOHIDSystem::scrollWheelEvent(short    deltaAxis1,
3638                                   short    deltaAxis2,
3639                                   short    deltaAxis3,
3640                    /* atTime */   AbsoluteTime ts)
3641
3642{
3643    scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, deltaAxis1<<16, deltaAxis2<<16, deltaAxis3<<16, 0, 0, 0, 0, ts, 0);
3644}
3645
3646void IOHIDSystem::scrollWheelEvent(short    deltaAxis1,
3647                                   short    deltaAxis2,
3648                                   short    deltaAxis3,
3649                                   IOFixed  fixedDelta1,
3650                                   IOFixed  fixedDelta2,
3651                                   IOFixed  fixedDelta3,
3652                                   SInt32   pointDeltaAxis1,
3653                                   SInt32   pointDeltaAxis2,
3654                                   SInt32   pointDeltaAxis3,
3655                                   UInt32   options,
3656                    /* atTime */   AbsoluteTime ts,
3657                                    OSObject *  sender)
3658
3659{
3660    IOHIDCmdGateActionArgs args;
3661
3662    args.arg0 = &deltaAxis1;
3663    args.arg1 = &deltaAxis2;
3664    args.arg2 = &deltaAxis3;
3665    args.arg3 = &fixedDelta1;
3666    args.arg4 = &fixedDelta2;
3667    args.arg5 = &fixedDelta3;
3668    args.arg6 = &pointDeltaAxis1;
3669    args.arg7 = &pointDeltaAxis2;
3670    args.arg8 = &pointDeltaAxis3;
3671    args.arg9 = &options;
3672    args.arg10 = &ts;
3673    args.arg11 = sender;
3674
3675    cmdGate->runAction((IOCommandGate::Action)doScrollWheelEvent, (void *)&args);
3676}
3677
3678IOReturn IOHIDSystem::doScrollWheelEvent(IOHIDSystem *self, void * args)
3679                        /* IOCommandGate::Action */
3680{
3681    short   deltaAxis1      = *(short *)((IOHIDCmdGateActionArgs *)args)->arg0;
3682    short   deltaAxis2      = *(short *)((IOHIDCmdGateActionArgs *)args)->arg1;
3683    short   deltaAxis3      = *(short *)((IOHIDCmdGateActionArgs *)args)->arg2;
3684    IOFixed fixedDelta1     = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg3;
3685    IOFixed fixedDelta2     = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg4;
3686    IOFixed fixedDelta3     = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg5;
3687    SInt32  pointDeltaAxis1 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg6;
3688    SInt32  pointDeltaAxis2 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg7;
3689    SInt32  pointDeltaAxis3 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg8;
3690    UInt32  options        = *(UInt32 *)((IOHIDCmdGateActionArgs *)args)->arg9;
3691    AbsoluteTime ts  = *(AbsoluteTime *)((IOHIDCmdGateActionArgs *)args)->arg10;
3692    OSObject * sender= (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg11;
3693
3694    self->scrollWheelEventGated(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3, pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender);
3695
3696    return kIOReturnSuccess;
3697}
3698
3699#if 0
3700#   define log_event_phase(s, ...)     kprintf("%s:%d " s, __FILE__, __LINE__, __VA_ARGS__)
3701#else
3702#   define log_event_phase(s, ...)
3703#endif
3704
3705void IOHIDSystem::scrollWheelEventGated(short   deltaAxis1,
3706                                        short   deltaAxis2,
3707                                        short   deltaAxis3,
3708                                       IOFixed  fixedDelta1,
3709                                       IOFixed  fixedDelta2,
3710                                       IOFixed  fixedDelta3,
3711                                       SInt32   pointDeltaAxis1,
3712                                       SInt32   pointDeltaAxis2,
3713                                       SInt32   pointDeltaAxis3,
3714                                       UInt32   options,
3715                        /* atTime */    AbsoluteTime ts,
3716                                        OSObject * sender)
3717{
3718    NXEventData wheelData;
3719    bool        moved = (deltaAxis1 || pointDeltaAxis1 ||
3720                         deltaAxis2 || pointDeltaAxis2 ||
3721                         deltaAxis3 || pointDeltaAxis3);
3722    UInt32      momentum = (options & kScrollTypeMomentumAny);
3723
3724    if (!eventsOpen)
3725        return;
3726
3727    if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
3728        return;
3729    }
3730
3731#if !WAKE_DISPLAY_ON_MOVEMENT
3732    if (!DISPLAY_IS_ENABLED) {
3733        if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0)
3734        {
3735           TICKLE_DISPLAY(NX_SCROLLWHEELMOVED);
3736        }
3737        return;
3738    }
3739#endif
3740
3741    /***********************************************************************************************
3742    BEGIN PHASE SUPPRESSION STATE MACHINE
3743        Quiet: (start)
3744            on May Begin:
3745                post May Begin
3746                goto Suspended
3747            on Began:
3748                if moved
3749                    post Begin
3750                    goto Begun
3751                else
3752                    post May Begin
3753                    goto Suspended
3754            on Continue:
3755            on Ended:
3756            on Canceled:
3757                log and post?
3758
3759        Suspended:
3760            on Began:
3761            on Continue:
3762                if moved:
3763                    post Begin
3764                    goto Begun
3765            on Ended:
3766            on Canceled:
3767                post Canceled
3768                goto Quiet
3769            on May Begin:
3770                log and post?
3771
3772
3773        Begun:
3774            on Ended
3775            on Canceled:
3776                post Ended or Cancelled
3777                goto Quiet
3778            on Continue:
3779                post Continue
3780            on Began:
3781            on May Begin:
3782                log and post?
3783
3784     */
3785    UInt32      phase = (options & kScrollTypeOptionPhaseAny);
3786    UInt32      oldDelayedPhase = 0;
3787    UInt32      newDelayedPhase = 0;
3788    if (_devicePhaseState && _devicePhaseState->getObject((OSSymbol*)sender)) {
3789        newDelayedPhase = oldDelayedPhase = ((OSNumber*)_devicePhaseState->getObject((OSSymbol*)sender))->unsigned32BitValue();
3790    }
3791    // phaseAnnotation = |32 supplied phase |24 original state |16 new state |8 empty |
3792    UInt32      phaseAnnotation = (phase << 16) | (oldDelayedPhase << 8);
3793
3794    switch (oldDelayedPhase) {
3795        default: // quiet
3796            switch (phase) {
3797                case kScrollTypeOptionPhaseMayBegin:
3798                    newDelayedPhase = kScrollTypeOptionPhaseMayBegin;
3799                    break;
3800                case kScrollTypeOptionPhaseBegan:
3801                    if (moved) {
3802                        newDelayedPhase = kScrollTypeOptionPhaseBegan;
3803                    }
3804                    else {
3805                        newDelayedPhase = kScrollTypeOptionPhaseMayBegin;
3806                        options &= ~kScrollTypeOptionPhaseAny;
3807                        options |= kScrollTypeOptionPhaseMayBegin;
3808                        phase = kScrollTypeOptionPhaseMayBegin;
3809                    }
3810                    break;
3811                case kScrollTypeOptionPhaseChanged:
3812                case kScrollTypeOptionPhaseEnded:
3813                case kScrollTypeOptionPhaseCanceled:
3814                    log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase);
3815                    break;
3816            }
3817            break;
3818
3819        case kScrollTypeOptionPhaseMayBegin: // suspended
3820            switch (phase) {
3821                case kScrollTypeOptionPhaseMayBegin:
3822                case kScrollTypeOptionPhaseBegan:
3823                case kScrollTypeOptionPhaseChanged:
3824                    if (moved) {
3825                        newDelayedPhase = kScrollTypeOptionPhaseBegan;
3826                        options &= ~kScrollTypeOptionPhaseAny;
3827                        options |= kScrollTypeOptionPhaseBegan;
3828                        phase = kScrollTypeOptionPhaseBegan;
3829                    }
3830                    else {
3831                        options &= ~kScrollTypeOptionPhaseAny;
3832                        phase = 0;
3833                    }
3834                    break;
3835                case kScrollTypeOptionPhaseEnded:
3836                case kScrollTypeOptionPhaseCanceled:
3837                    newDelayedPhase = 0;
3838                    options &= ~kScrollTypeOptionPhaseAny;
3839                    options |= kScrollTypeOptionPhaseCanceled;
3840                    phase = kScrollTypeOptionPhaseCanceled;
3841                    break;
3842            }
3843            break;
3844
3845        case kScrollTypeOptionPhaseBegan: // Begun
3846            switch (phase) {
3847                case kScrollTypeOptionPhaseMayBegin:
3848                case kScrollTypeOptionPhaseBegan:
3849                    log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase);
3850                    break;
3851                case kScrollTypeOptionPhaseChanged:
3852                    break;
3853                case kScrollTypeOptionPhaseEnded:
3854                case kScrollTypeOptionPhaseCanceled:
3855                    newDelayedPhase = 0;
3856                    break;
3857            }
3858            break;
3859    }
3860    phaseAnnotation |= phase | (newDelayedPhase >> 8);
3861    if (oldDelayedPhase != newDelayedPhase) {
3862        log_event_phase("updating phase from %04x to %04x for %p\n", oldDelayedPhase, newDelayedPhase, sender);
3863        if (newDelayedPhase) {
3864            if (!_devicePhaseState)
3865                _devicePhaseState = OSDictionary::withCapacity(0);
3866            if (_devicePhaseState) {
3867                OSNumber *newDelayedPhaseNumber = OSNumber::withNumber(newDelayedPhase, 32);
3868                _devicePhaseState->setObject((OSSymbol*)sender, newDelayedPhaseNumber);
3869                newDelayedPhaseNumber->release();
3870            }
3871            else {
3872                IOLog("%s unable to create _devicePhaseState dictionary\n", __func__);
3873            }
3874        }
3875        else {
3876            if (_devicePhaseState) {
3877                _devicePhaseState->removeObject((OSSymbol*)sender);
3878            }
3879        }
3880    }
3881    /*
3882     END PHASE SUPPRESSION STATE MACHINE
3883     **********************************************************************************************/
3884
3885    switch (momentum) {
3886        case kScrollTypeMomentumStart:
3887            if (!moved) {
3888                // suppress the start until we get a changed with movement
3889                _delayedScrollMomentum = momentum;
3890                momentum = 0;
3891                options &= ~kScrollTypeMomentumAny;
3892            }
3893            else {
3894                // clear state and let go
3895                _delayedScrollMomentum = 0;
3896            }
3897            break;
3898
3899        case kScrollTypeMomentumContinue:
3900            if (_delayedScrollMomentum) {
3901                // we suppressed a start
3902                options &= ~kScrollTypeMomentumAny;
3903                if (!moved) {
3904                    // continue suppressing it
3905                    momentum = 0;
3906                }
3907                else {
3908                    // make this the start
3909                    momentum = _delayedScrollMomentum;
3910                    options |= momentum;
3911                    // clear the state
3912                    _delayedScrollMomentum = 0;
3913                }
3914            }
3915            else {
3916                if (!moved) {
3917                    // if there is phase, we will allow this event to go through
3918                    // without changing it. if there isn't, it will get suppressed below.
3919                    momentum = 0;
3920                }
3921            }
3922            break;
3923
3924        case kScrollTypeMomentumEnd:
3925            if (_delayedScrollMomentum) {
3926                // we have a suppressed start. the whole scroll needs to be suppressed.
3927                options &= ~kScrollTypeMomentumAny;
3928                momentum = 0;
3929                _delayedScrollMomentum = 0;
3930            }
3931            else {
3932                // do nothing
3933            }
3934
3935            break;
3936
3937        case 0:
3938            // no momentum. do nothing.
3939            break;
3940
3941        default:
3942            kprintf("IOHIDSystem::scrollWheelEventGated called with unknown momentum state: %08x\n", (unsigned)momentum);
3943            break;
3944    }
3945
3946    /***********************************************************************************************
3947     BEGIN SCROLL COUNT STATE MACHINE
3948     */
3949    UInt32 phase_momentum = options & (_scIgnoreMomentum ? kScrollTypeOptionPhaseAny : (kScrollTypeOptionPhaseAny | kScrollTypeMomentumAny));
3950    if (phase_momentum) {
3951        UInt64  axis1squared = (pointDeltaAxis1 * pointDeltaAxis1);
3952        UInt64  axis2squared = (pointDeltaAxis2 * pointDeltaAxis2);
3953        UInt64  axis3squared = (pointDeltaAxis3 * pointDeltaAxis3);
3954        UInt64  scrollMagnitudeSquared = axis1squared + axis2squared + axis3squared;
3955        UInt8   newDirection = kScrollDirectionInvalid;
3956        bool    checkSustain = false;
3957
3958        if ((axis1squared > axis2squared) && (axis1squared > axis3squared)) {
3959            if (pointDeltaAxis1 > 0) {
3960                newDirection = kScrollDirectionXPositive;
3961            }
3962            else if (pointDeltaAxis1 < 0) {
3963                newDirection = kScrollDirectionXNegative;
3964            }
3965        }
3966        else if ((axis2squared > axis1squared) && (axis2squared > axis3squared)) {
3967            if (pointDeltaAxis2 > 0) {
3968                newDirection = kScrollDirectionYPositive;
3969            }
3970            else if (pointDeltaAxis2 < 0) {
3971                newDirection = kScrollDirectionYNegative;
3972            }
3973        }
3974        else if ((axis3squared > axis1squared) && (axis3squared > axis2squared)) {
3975            if (pointDeltaAxis3 > 0) {
3976                newDirection = kScrollDirectionZPositive;
3977            }
3978            else if (pointDeltaAxis3 < 0) {
3979                newDirection = kScrollDirectionZNegative;
3980            }
3981        }
3982        if ((newDirection != kScrollDirectionInvalid) && (newDirection != _scDirection)) {
3983            if (_scCount) {
3984                log_scroll_state("Resetting _scCount on change from %d to %d\n", _scDirection, newDirection);
3985                _scCount = 0;
3986            }
3987            _scDirection = newDirection;
3988        }
3989
3990        if (_scCount && _scMouseCanReset) {
3991            IOFixedPoint64 thresh = IOFixedPoint64().fromIntFloor(clickSpaceThresh.x, clickSpaceThresh.y);
3992            IOFixedPoint64 min = _scLastScrollLocation - thresh;
3993            IOFixedPoint64 max = _scLastScrollLocation + thresh;
3994            IOFixedPoint64 location = _cursorHelper.desktopLocation();
3995            if ( (location > max) || (location < min) ) {
3996                log_scroll_state("Resetting _scCount on mouse move [%d, %d] vs [%d, %d]\n",
3997                                 location.xValue().as32(), location.yValue().as32(),
3998                                 _scLastScrollLocation.xValue().as32(), _scLastScrollLocation.yValue().as32());
3999                _scCount = 0;
4000            }
4001        }
4002
4003        switch (phase_momentum) {
4004            case kScrollTypeOptionPhaseBegan: {
4005                if (_scCount > 0) {
4006                    if ((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) {
4007                        if (!_scIncrementedThisPhrase) {
4008                            log_scroll_state("Incrementing _scCount: %lld\n", ts);
4009                            _scCount++;
4010                            _scIncrementedThisPhrase = 1;
4011                        }
4012                        _scLastScrollSustainTime = ts;
4013                    }
4014                    else {
4015                        _scCount = 0;
4016                        log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts);
4017                    }
4018                }
4019                break;
4020            }
4021            case kScrollTypeOptionPhaseChanged: {
4022                if (_scCount == 0) {
4023                    if (scrollMagnitudeSquared >= _scMinDeltaSqToStart) {
4024                        log_scroll_state("_scCount to 1 on %lld > %lld\n", scrollMagnitudeSquared, _scMinDeltaSqToStart);
4025                        _scCount = 1;
4026                        _scLastScrollSustainTime = ts;
4027                    }
4028                }
4029                else {
4030                    if (_scCount > 2) {
4031                        IOFixed64 temp;
4032                        temp.fromIntFloor(llsqrt(scrollMagnitudeSquared));
4033                        temp /= _scAccelerationFactor;
4034                        _scCount += temp.as32();
4035                        log_scroll_state("_scCount to %d on (llsqrt(%lld) * 65536 / %lld)\n", _scCount, scrollMagnitudeSquared, _scAccelerationFactor.asFixed64());
4036                        if (_scCount > _scCountMax) {
4037                            _scCount = _scCountMax;
4038                        }
4039                    }
4040                    checkSustain = true;
4041                }
4042                break;
4043            }
4044            case kScrollTypeOptionPhaseEnded: {
4045                if (_scCount > 0) {
4046                    _scLastScrollEndTime = ts;
4047                    _scIncrementedThisPhrase = 0;
4048                }
4049                break;
4050            }
4051            case kScrollTypeOptionPhaseCanceled: {
4052                log_scroll_state("Resetting _scCount cancelled: %lld\n", ts);
4053                _scIncrementedThisPhrase = false;
4054                _scCount = 0;
4055                break;
4056            }
4057            case kScrollTypeOptionPhaseMayBegin: {
4058                if (_scCount > 0) {
4059                    if (((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) && !_scIncrementedThisPhrase) {
4060                        log_scroll_state("Incrementing _scCount: %lld\n", ts);
4061                        _scCount++;
4062                        _scIncrementedThisPhrase = 1;
4063                        _scLastScrollSustainTime = ts;
4064                    }
4065                    else {
4066                        log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts);
4067                        _scCount = 0;
4068                        _scIncrementedThisPhrase = 0;
4069                    }
4070                }
4071                break;
4072            }
4073            case kScrollTypeMomentumStart: {
4074                // do nothing
4075                break;
4076            }
4077            case kScrollTypeMomentumContinue: {
4078                checkSustain = true;
4079                break;
4080            }
4081            case kScrollTypeMomentumEnd: {
4082                if (_scCount > 0) {
4083                    _scLastScrollEndTime = ts;
4084                    _scIncrementedThisPhrase = 0;
4085                }
4086                break;
4087            }
4088        }
4089
4090        if (checkSustain) {
4091            if (scrollMagnitudeSquared > _scMinDeltaSqToSustain) {
4092                _scLastScrollSustainTime = ts;
4093            }
4094            else if (_scLastScrollSustainTime + _scMaxTimeDeltaToSustain < ts) {
4095                log_scroll_state("Resetting _scCount due to sustain delay: %lld + %lld < %lld\n", _scLastScrollSustainTime, _scMaxTimeDeltaToSustain, ts);
4096                _scCount = 0;
4097            }
4098        }
4099        _scLastScrollLocation = _cursorHelper.desktopLocation();
4100    }
4101    /*
4102     END SCROLL COUNT STATE MACHINE
4103     **********************************************************************************************/
4104
4105    if (!moved && !momentum && !phase) {
4106        log_event_phase("annotation %08x suppressed\n", phaseAnnotation);
4107        return;
4108    }
4109    else {
4110        log_event_phase("annotation %08x posted with %08x\n", phaseAnnotation, options);
4111    }
4112
4113    TICKLE_DISPLAY(NX_SCROLLWHEELMOVED);
4114
4115    bzero((char *)&wheelData, sizeof wheelData);
4116    wheelData.scrollWheel.deltaAxis1 = deltaAxis1;
4117    wheelData.scrollWheel.deltaAxis2 = deltaAxis2;
4118    wheelData.scrollWheel.deltaAxis3 = deltaAxis3;
4119    wheelData.scrollWheel.fixedDeltaAxis1 = fixedDelta1;
4120    wheelData.scrollWheel.fixedDeltaAxis2 = fixedDelta2;
4121    wheelData.scrollWheel.fixedDeltaAxis3 = fixedDelta3;
4122    wheelData.scrollWheel.pointDeltaAxis1 = pointDeltaAxis1;
4123    wheelData.scrollWheel.pointDeltaAxis2 = pointDeltaAxis2;
4124    wheelData.scrollWheel.pointDeltaAxis3 = pointDeltaAxis3;
4125    wheelData.scrollWheel.reserved1       = (UInt16)options & (kScrollTypeContinuous | kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny);
4126    updateScrollEventForSender(sender, &wheelData);
4127
4128    if (options & (kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny)) {
4129        wheelData.scrollWheel.reserved8[0]  = phaseAnnotation;
4130        wheelData.scrollWheel.reserved8[1]  = _scCount;
4131        log_scroll_state("posting scroll: (%d, %d, %d) %d %d, %lld %lld, %lld\n",
4132                         pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, _scCount, _scDirection,
4133                         _scLastScrollEndTime, _scLastScrollSustainTime, ts);
4134        wheelData.scrollWheel.reserved8[2]  = IOHIDevice::GenerateKey(sender);
4135    }
4136
4137    postEvent(             (options & kScrollTypeZoom) ? NX_ZOOM : NX_SCROLLWHEELMOVED,
4138            /* at */       &_cursorHelper.desktopLocation(),
4139            /* atTime */   ts,
4140            /* withData */ &wheelData,
4141            /* sender */   sender);
4142
4143    return;
4144}
4145
4146void IOHIDSystem::_tabletEvent(IOHIDSystem *self,
4147                               NXEventData *tabletData,
4148                               AbsoluteTime ts,
4149                               OSObject * sender,
4150                               void *     refcon __unused)
4151{
4152    self->tabletEvent(tabletData, ts, sender);
4153}
4154
4155void IOHIDSystem::tabletEvent(NXEventData *tabletData,
4156                              AbsoluteTime ts)
4157{
4158    tabletEvent(tabletData, ts, 0);
4159}
4160
4161void IOHIDSystem::tabletEvent(NXEventData *tabletData,
4162                              AbsoluteTime ts,
4163                              OSObject * sender)
4164{
4165    cmdGate->runAction((IOCommandGate::Action)doTabletEvent, tabletData, &ts, sender);
4166}
4167
4168IOReturn IOHIDSystem::doTabletEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2)
4169                        /* IOCommandGate::Action */
4170{
4171    NXEventData *tabletData     = (NXEventData *) arg0;
4172    AbsoluteTime ts     = *(AbsoluteTime *) arg1;
4173    OSObject * sender       = (OSObject *) arg2;
4174
4175    self->tabletEventGated(tabletData, ts, sender);
4176
4177    return kIOReturnSuccess;
4178}
4179
4180void IOHIDSystem::tabletEventGated(NXEventData *tabletData,
4181                                    AbsoluteTime ts,
4182                                    OSObject * sender)
4183{
4184    CachedMouseEventStruct  *cachedMouseEvent;
4185
4186    if (!eventsOpen)
4187        return;
4188
4189    if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline))
4190        return;
4191
4192    if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) &&
4193        !(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag))
4194    {
4195
4196        cachedMouseEvent->state     |= kCachedMouseTabletEventDispFlag;
4197        cachedMouseEvent->subType   = NX_SUBTYPE_TABLET_POINT;
4198        bcopy( tabletData, &(cachedMouseEvent->tabletData), sizeof(NXEventData));
4199
4200        // Don't dispatch an event if they can be embedded in pointing events
4201        if ( cachedMouseEvent->state & kCachedMousePointingEventDispFlag )
4202            return;
4203    }
4204
4205    postEvent(NX_TABLETPOINTER,
4206              &_cursorHelper.desktopLocation(),
4207              ts,
4208              tabletData,
4209              sender);
4210
4211    return;
4212}
4213
4214void IOHIDSystem::_proximityEvent(IOHIDSystem *self,
4215                                  NXEventData *proximityData,
4216                                  AbsoluteTime ts,
4217                                  OSObject * sender,
4218                                  void *     refcon __unused)
4219{
4220    self->proximityEvent(proximityData, ts, sender);
4221}
4222
4223void IOHIDSystem::proximityEvent(NXEventData *proximityData,
4224                                 AbsoluteTime ts)
4225{
4226
4227    proximityEvent(proximityData, ts, 0);
4228}
4229
4230void IOHIDSystem::proximityEvent(NXEventData *proximityData,
4231                                 AbsoluteTime ts,
4232                                 OSObject * sender)
4233{
4234    cmdGate->runAction((IOCommandGate::Action)doProximityEvent, proximityData, &ts, sender);
4235}
4236
4237IOReturn IOHIDSystem::doProximityEvent(IOHIDSystem *self, void * arg0, void *arg1, void * arg2)
4238                        /* IOCommandGate::Action */
4239{
4240
4241    NXEventData *proximityData  = (NXEventData *)arg0;
4242    AbsoluteTime ts     = *(AbsoluteTime *)arg1;
4243    OSObject * sender       = (OSObject *)arg2;
4244
4245    self->proximityEventGated(proximityData, ts, sender);
4246
4247    return kIOReturnSuccess;
4248}
4249
4250void IOHIDSystem::proximityEventGated(NXEventData *proximityData,
4251                                        AbsoluteTime ts,
4252                                        OSObject * sender)
4253{
4254    CachedMouseEventStruct  *cachedMouseEvent;
4255
4256    if (!eventsOpen)
4257        return;
4258
4259    if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline))
4260        return;
4261
4262    if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) &&
4263        !(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag))
4264    {
4265        cachedMouseEvent->state     |= kCachedMouseTabletEventDispFlag;
4266        cachedMouseEvent->subType   = NX_SUBTYPE_TABLET_PROXIMITY;
4267        bcopy( proximityData, &(cachedMouseEvent->proximityData), sizeof(NXEventData));
4268    }
4269
4270    postEvent(NX_TABLETPROXIMITY,
4271              &_cursorHelper.desktopLocation(),
4272              ts,
4273              proximityData,
4274              sender);
4275
4276    return;
4277}
4278
4279void IOHIDSystem::doProcessKeyboardEQ(IOHIDSystem * self)
4280{
4281    processKeyboardEQ(self);
4282}
4283
4284void IOHIDSystem::processKeyboardEQ(IOHIDSystem * self, AbsoluteTime * deadline)
4285{
4286    KeyboardEQElement * keyboardEQElement;
4287
4288    KEYBOARD_EQ_LOCK;
4289
4290    while ( ((keyboardEQElement = (KeyboardEQElement *)dequeue_head(&gKeyboardEQ)) != NULL)
4291           && !(deadline && (CMP_ABSOLUTETIME(&(keyboardEQElement->ts), deadline) > 0)))
4292    {
4293        KEYBOARD_EQ_UNLOCK;
4294
4295        if (keyboardEQElement->action)
4296            (*(keyboardEQElement->action))(self, keyboardEQElement);
4297        OSSafeReleaseNULL(keyboardEQElement->sender); // NOTE: This is the matching release
4298
4299        IOFree(keyboardEQElement, sizeof(KeyboardEQElement));
4300
4301        KEYBOARD_EQ_LOCK;
4302    }
4303
4304    KEYBOARD_EQ_UNLOCK;
4305}
4306
4307
4308//
4309// Process a keyboard state change.
4310//
4311void IOHIDSystem::_keyboardEvent(IOHIDSystem * self,
4312                                unsigned   eventType,
4313         /* flags */            unsigned   flags,
4314         /* keyCode */          unsigned   key,
4315         /* charCode */         unsigned   charCode,
4316         /* charSet */          unsigned   charSet,
4317         /* originalCharCode */ unsigned   origCharCode,
4318         /* originalCharSet */  unsigned   origCharSet,
4319         /* keyboardType */     unsigned   keyboardType,
4320         /* repeat */           bool       repeat,
4321         /* atTime */           AbsoluteTime ts,
4322                                OSObject * sender,
4323                                void *     refcon __unused)
4324{
4325    self->keyboardEvent(eventType, flags, key, charCode, charSet,
4326                        origCharCode, origCharSet, keyboardType, repeat, ts, sender);
4327}
4328
4329void IOHIDSystem::keyboardEvent(unsigned   eventType,
4330         /* flags */            unsigned   flags,
4331         /* keyCode */          unsigned   key,
4332         /* charCode */         unsigned   charCode,
4333         /* charSet */          unsigned   charSet,
4334         /* originalCharCode */ unsigned   origCharCode,
4335         /* originalCharSet */  unsigned   origCharSet,
4336         /* keyboardType */     unsigned   keyboardType,
4337         /* repeat */           bool       repeat,
4338         /* atTime */           AbsoluteTime ts)
4339{
4340    keyboardEvent(eventType, flags, key, charCode, charSet,
4341                origCharCode, origCharSet, keyboardType, repeat, ts, 0);
4342}
4343
4344void IOHIDSystem::keyboardEvent(unsigned   eventType,
4345         /* flags */            unsigned   flags,
4346         /* keyCode */          unsigned   key,
4347         /* charCode */         unsigned   charCode,
4348         /* charSet */          unsigned   charSet,
4349         /* originalCharCode */ unsigned   origCharCode,
4350         /* originalCharSet */  unsigned   origCharSet,
4351         /* keyboardType */     unsigned   keyboardType,
4352         /* repeat */           bool       repeat,
4353         /* atTime */           AbsoluteTime ts,
4354         /* sender */       OSObject * sender)
4355{
4356    KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
4357
4358    if ( !keyboardEQElement )
4359        return;
4360
4361    bzero(keyboardEQElement, sizeof(KeyboardEQElement));
4362
4363    keyboardEQElement->action   = IOHIDSystem::doKeyboardEvent;
4364    keyboardEQElement->ts       = ts;
4365    keyboardEQElement->sender   = sender;
4366    if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ
4367
4368
4369    keyboardEQElement->event.keyboard.eventType     = eventType;
4370    keyboardEQElement->event.keyboard.flags         = flags;
4371    keyboardEQElement->event.keyboard.key           = key;
4372    keyboardEQElement->event.keyboard.charCode      = charCode;
4373    keyboardEQElement->event.keyboard.charSet       = charSet;
4374    keyboardEQElement->event.keyboard.origCharCode  = origCharCode;
4375    keyboardEQElement->event.keyboard.origCharSet   = origCharSet;
4376    keyboardEQElement->event.keyboard.keyboardType  = keyboardType;
4377    keyboardEQElement->event.keyboard.repeat        = repeat;
4378
4379    KEYBOARD_EQ_LOCK;
4380    enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
4381    KEYBOARD_EQ_UNLOCK;
4382
4383    keyboardEQES->interruptOccurred(0, 0, 0);
4384}
4385
4386IOReturn IOHIDSystem::doKeyboardEvent(IOHIDSystem *self, void * args)
4387                        /* IOCommandGate::Action */
4388{
4389    KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
4390
4391    AbsoluteTime ts         = keyboardEQElement->ts;
4392    OSObject * sender       = keyboardEQElement->sender;
4393
4394    unsigned   eventType    = keyboardEQElement->event.keyboard.eventType;
4395    unsigned   flags        = keyboardEQElement->event.keyboard.flags;
4396    unsigned   key          = keyboardEQElement->event.keyboard.key;
4397    unsigned   charCode     = keyboardEQElement->event.keyboard.charCode;
4398    unsigned   charSet      = keyboardEQElement->event.keyboard.charSet;
4399    unsigned   origCharCode = keyboardEQElement->event.keyboard.origCharCode;
4400    unsigned   origCharSet  = keyboardEQElement->event.keyboard.origCharSet;
4401    unsigned   keyboardType = keyboardEQElement->event.keyboard.keyboardType;
4402    bool       repeat       = keyboardEQElement->event.keyboard.repeat;
4403
4404    self->keyboardEventGated(eventType, flags, key, charCode, charSet,
4405                origCharCode, origCharSet, keyboardType, repeat, ts, sender);
4406
4407    return kIOReturnSuccess;
4408}
4409
4410/* This method adds a key press to the consumedKeys array, indicating that a
4411 * key down event was consumed and its corresponding key up must be consumed.
4412 * It returns true if the key was added successfully, and false if the key
4413 * couldn't be allocated or was already in the array.
4414 */
4415bool IOHIDSystem::addConsumedKey(unsigned key)
4416{
4417    bool result = false;
4418    OSNumber *keyCodeNumber;
4419    unsigned int index;
4420
4421    keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8);
4422    if ( !keyCodeNumber ) goto finish;
4423
4424    index = getArrayIndexForObject(consumedKeys, keyCodeNumber);
4425    if ( index != kObjectNotFound ) goto finish;
4426
4427    consumedKeys->setObject(keyCodeNumber);
4428    result = true;
4429finish:
4430    if (keyCodeNumber) keyCodeNumber->release();
4431    return result;
4432}
4433
4434/* This method removes a key press from the consumed keys array, indicating
4435 * that a key down / key up pair have been consumed. It returns true when the
4436 * key is successfully removed from the array, and false if the key was not in
4437 * the array.
4438 */
4439bool IOHIDSystem::removeConsumedKey(unsigned key)
4440{
4441    bool result = false;
4442    OSNumber *keyCodeNumber;
4443    unsigned int index;
4444
4445    keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8);
4446    if ( !keyCodeNumber ) goto finish;
4447
4448    index = getArrayIndexForObject(consumedKeys, keyCodeNumber);
4449    if ( index == kObjectNotFound ) goto finish;
4450
4451    consumedKeys->removeObject(index);
4452    result = true;
4453finish:
4454    if (keyCodeNumber) keyCodeNumber->release();
4455    return result;
4456}
4457
4458void IOHIDSystem::keyboardEventGated(unsigned   eventType,
4459                                /* flags */            unsigned   flags,
4460                                /* keyCode */          unsigned   key,
4461                                /* charCode */         unsigned   charCode,
4462                                /* charSet */          unsigned   charSet,
4463                                /* originalCharCode */ unsigned   origCharCode,
4464                                /* originalCharSet */  unsigned   origCharSet,
4465                                /* keyboardType */  unsigned   keyboardType,
4466                                /* repeat */           bool       repeat,
4467                                /* atTime */           AbsoluteTime ts,
4468                                /* sender */           OSObject * sender)
4469{
4470    UInt32 rootDomainConsumeCause;
4471    UInt32 displayConsumeCause;
4472    NXEventData outData;
4473    static unsigned prevFlags = 0;
4474
4475    /* If we get a key up event, check the consumedKeys array to see if it
4476     * needs to be consumed.
4477     */
4478    if ( eventType == NX_KEYUP && consumedKeys->getCount() ) {
4479        if (removeConsumedKey(key)) {
4480        return;
4481        }
4482    }
4483
4484    /* The goal here is to ignore the key presses that woke the system, and for
4485     * that purpose we are interested in two deadlines. First, we want to
4486     * consume the first key press that occurs within a second of the
4487     * rootDomain domain powering on, which will prevent the key press that
4488     * wakes the machine from posting event. Second, we want to consume any key
4489     * presses that occur within 50ms of that first key press or of the
4490     * displayWrangler powering on.  This prevents a hand smashing the keyboard
4491     * from generating lots of spurious events both on wake from sleep and
4492     * display sleep.
4493     */
4494    rootDomainConsumeCause = ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline);
4495    displayConsumeCause = ShouldConsumeHIDEvent(ts, displayStateChangeDeadline);
4496    if (rootDomainConsumeCause || displayConsumeCause) {
4497        TICKLE_DISPLAY(NX_KEYDOWN);
4498        if (eventType != NX_KEYDOWN) return;
4499
4500        (void) addConsumedKey(key);
4501
4502        if (rootDomainConsumeCause) {
4503            AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0;
4504
4505            clock_get_uptime(&displayStateChangeDeadline);
4506            ADD_ABSOLUTETIME(&displayStateChangeDeadline,
4507                &gIOHIDRelativeTickleThresholdAbsoluteTime);
4508            }
4509
4510            return;
4511        }
4512
4513    // Notify stackshotd for CMD-OPT-CTRL-ALT-(COMMA|SLASH|PERIOD)
4514    if( !repeat && ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK) )
4515    {
4516        UInt32 keycode = UINT_MAX;
4517        switch (key) {
4518            case 0x2f: // kHIDUsage_KeyboardPeriod
4519            case 0x41: // kHIDUsage_KeypadPeriod
4520                keycode = kHIDUsage_KeyboardPeriod;
4521                break;
4522            case 0x2b: // kHIDUsage_KeyboardComma
4523            case 0x5f: // kHIDUsage_KeypadComma
4524                keycode = kHIDUsage_KeyboardComma;
4525                break;
4526            case 0x2c: // kHIDUsage_KeyboardSlash
4527            case 0x4b: // kHIDUsage_KeypadSlash
4528                keycode = kHIDUsage_KeyboardSlash;
4529                break;
4530            default:
4531                // do nothing
4532                break;
4533        }
4534        if (keycode != UINT_MAX) {
4535            if (eventType == NX_KEYDOWN) {
4536                sendStackShotMessage(keycode);
4537                IOLog("IOHIDSystem posted stackshot event 0x%02x\n", (unsigned)keycode);
4538            }
4539            return;
4540        }
4541    }
4542
4543    /* If the display is off, we consume a key down event and send a tickle to
4544     * wake the displays. Key up events are also consumed on the rare chance
4545     * they aren't in the consumedKeys array, but they don't cause a tickle.
4546    */
4547    if ( !DISPLAY_IS_ENABLED ) {
4548        if ( eventType == NX_KEYDOWN ) {
4549            (void) addConsumedKey(key);
4550        }
4551        else if ( eventType == NX_KEYUP) {
4552            return;
4553        }
4554        else if ( eventType == NX_FLAGSCHANGED ) {
4555            unsigned kbFlagChanges = (flags & KEYBOARD_FLAGSMASK) ^ (prevFlags & KEYBOARD_FLAGSMASK);
4556
4557            /* Flag changes due to key release shouldn't tickle display */
4558            if (!(kbFlagChanges & flags)) {
4559                prevFlags = flags;
4560                return;
4561            }
4562        }
4563        TICKLE_DISPLAY(eventType);
4564        return;
4565    }
4566    prevFlags = flags;
4567
4568    TICKLE_DISPLAY(NX_KEYDOWN);
4569
4570    // RY: trigger NMI for CMD-OPT-CTRL-ALT-ESC
4571    if( !repeat && (key == 0x35) &&
4572        (eventType == NX_KEYDOWN) &&
4573        ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK))
4574    {
4575        PE_enter_debugger("USB Programmer Key");
4576    }
4577
4578    if ( eventsOpen ) {
4579        UInt32 usage = 0;
4580        UInt32 usagePage = 0;
4581        if ((flags & NX_HIGHCODE_ENCODING_MASK) == NX_HIGHCODE_ENCODING_MASK) {
4582            usage = (origCharCode & 0xffff0000) >> 16;
4583            usagePage = (origCharSet & 0xffff0000) >> 16;
4584            origCharCode &= 0xffff;
4585            origCharSet &= 0xffff;
4586        }
4587
4588        outData.key.repeat = repeat;
4589        outData.key.keyCode = key;
4590        outData.key.charSet = charSet;
4591        outData.key.charCode = charCode;
4592        outData.key.origCharSet = origCharSet;
4593        outData.key.origCharCode = origCharCode;
4594        outData.key.keyboardType = keyboardType;
4595        outData.key.reserved2 = usage;
4596        outData.key.reserved3 = usagePage;
4597
4598        evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
4599                | (flags & KEYBOARD_FLAGSMASK);
4600
4601        if (cachedEventFlags != evg->eventFlags) {
4602            cachedEventFlags = evg->eventFlags;
4603
4604            // RY: Reset the clickTime as well on modifier
4605            // change to prevent double click from occuring
4606            nanoseconds_to_absolutetime(0, &clickTime);
4607        }
4608
4609        postEvent(         eventType,
4610            /* at */       &_cursorHelper.desktopLocation(),
4611            /* atTime */   ts,
4612            /* withData */ &outData,
4613            /* sender */   sender,
4614            /* extPID */   0,
4615            /* processKEQ*/false);
4616    } else {
4617        // Take on BSD console duties and dispatch the keyboardEvents.
4618        static const char cursorCodes[] = { 'D', 'A', 'C', 'B' };
4619        if( (eventType == NX_KEYDOWN) && ((flags & NX_ALTERNATEMASK) != NX_ALTERNATEMASK)) {
4620            if( (charSet == NX_SYMBOLSET)
4621                && (charCode >= 0xac) && (charCode <= 0xaf)) {
4622                cons_cinput( '\033');
4623                cons_cinput( 'O');
4624                charCode = cursorCodes[ charCode - 0xac ];
4625            }
4626            cons_cinput( charCode );
4627        }
4628    }
4629}
4630
4631void IOHIDSystem::_keyboardSpecialEvent(  IOHIDSystem * self,
4632                      unsigned   eventType,
4633                       /* flags */        unsigned   flags,
4634                       /* keyCode  */     unsigned   key,
4635                       /* specialty */    unsigned   flavor,
4636                       /* guid */         UInt64     guid,
4637                       /* repeat */       bool       repeat,
4638                       /* atTime */       AbsoluteTime ts,
4639                      OSObject * sender,
4640                      void *     refcon __unused)
4641{
4642    self->keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, sender);
4643}
4644
4645void IOHIDSystem::keyboardSpecialEvent(   unsigned   eventType,
4646                       /* flags */        unsigned   flags,
4647                       /* keyCode  */     unsigned   key,
4648                       /* specialty */    unsigned   flavor,
4649                       /* guid */         UInt64     guid,
4650                       /* repeat */       bool       repeat,
4651                       /* atTime */       AbsoluteTime ts)
4652{
4653    keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, 0);
4654}
4655
4656void IOHIDSystem::keyboardSpecialEvent(   unsigned   eventType,
4657                       /* flags */        unsigned   flags,
4658                       /* keyCode  */     unsigned   key,
4659                       /* specialty */    unsigned   flavor,
4660                       /* guid */         UInt64     guid,
4661                       /* repeat */       bool       repeat,
4662                       /* atTime */       AbsoluteTime ts,
4663                       /* sender */       OSObject * sender)
4664{
4665    KeyboardEQElement * keyboardEQElement = NULL;
4666
4667    keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
4668
4669    if ( !keyboardEQElement )
4670        return;
4671
4672    bzero(keyboardEQElement, sizeof(KeyboardEQElement));
4673
4674    keyboardEQElement->action   = IOHIDSystem::doKeyboardSpecialEvent;
4675    keyboardEQElement->ts       = ts;
4676    keyboardEQElement->sender   = sender;
4677    if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ
4678
4679    keyboardEQElement->event.keyboardSpecial.eventType  = eventType;
4680    keyboardEQElement->event.keyboardSpecial.flags      = flags;
4681    keyboardEQElement->event.keyboardSpecial.key        = key;
4682    keyboardEQElement->event.keyboardSpecial.flavor     = flavor;
4683    keyboardEQElement->event.keyboardSpecial.guid       = guid;
4684    keyboardEQElement->event.keyboardSpecial.repeat     = repeat;
4685
4686    KEYBOARD_EQ_LOCK;
4687    enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
4688    KEYBOARD_EQ_UNLOCK;
4689
4690    keyboardEQES->interruptOccurred(0, 0, 0);
4691}
4692
4693
4694IOReturn IOHIDSystem::doKeyboardSpecialEvent(IOHIDSystem *self, void * args)
4695                        /* IOCommandGate::Action */
4696{
4697    KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
4698
4699    AbsoluteTime    ts          = keyboardEQElement->ts;
4700    OSObject *      sender      = keyboardEQElement->sender;
4701
4702    unsigned        eventType   = keyboardEQElement->event.keyboardSpecial.eventType;
4703    unsigned        flags       = keyboardEQElement->event.keyboardSpecial.flags;
4704    unsigned        key         = keyboardEQElement->event.keyboardSpecial.key;
4705    unsigned        flavor      = keyboardEQElement->event.keyboardSpecial.flavor;
4706    UInt64          guid        = keyboardEQElement->event.keyboardSpecial.guid;
4707    bool            repeat      = keyboardEQElement->event.keyboardSpecial.repeat;
4708
4709    self->keyboardSpecialEventGated(eventType, flags, key, flavor, guid, repeat, ts, sender);
4710
4711    return kIOReturnSuccess;
4712}
4713
4714void IOHIDSystem::keyboardSpecialEventGated(
4715                                /* event */     unsigned   eventType,
4716                                /* flags */     unsigned   flags,
4717                                /* keyCode  */  unsigned   key,
4718                                /* specialty */ unsigned   flavor,
4719                                /* guid */      UInt64     guid,
4720                                /* repeat */    bool       repeat,
4721                                /* atTime */    AbsoluteTime ts,
4722                                /* sender */    OSObject * sender)
4723{
4724    NXEventData outData;
4725    int     level = -1;
4726
4727    if ((key != NX_NOSPECIALKEY) || (flavor != NX_SUBTYPE_STICKYKEYS_RELEASE)) {
4728        /* Key up events shouldn't tickle when display is off */
4729        if (DISPLAY_IS_ENABLED || eventType == NX_KEYDOWN)
4730            TICKLE_DISPLAY(NX_SYSDEFINED);
4731    }
4732
4733    if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline) ||
4734        !DISPLAY_IS_ENABLED)
4735    {
4736        return;
4737    }
4738
4739    // Since the HIDSystem will now take on BSD Console duty,
4740    // we need to make sure to process the programmer key info
4741    // prior to doing the eventsOpen check
4742    if ( eventType == NX_KEYDOWN && flavor == NX_POWER_KEY && !repeat) {
4743        if ( (flags & (NORMAL_MODIFIER_MASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) ==
4744              (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK) )
4745            PE_enter_debugger("Programmer Key");
4746        else if ( (flags & NORMAL_MODIFIER_MASK) == ( NX_COMMANDMASK | NX_CONTROLMASK ) )
4747            PEHaltRestart(kPERestartCPU);
4748    }
4749
4750    if ( !eventsOpen )
4751        return;
4752
4753    // clear event record
4754    bzero( (void *)&outData, sizeof outData );
4755
4756    // Update flags.
4757    evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
4758            | (flags & KEYBOARD_FLAGSMASK);
4759
4760    // was this a keydown event
4761    if ( eventType == NX_KEYDOWN )
4762    {
4763        notifyHIDevices(this, ioHIDevices, kIOHIDSystem508SpecialKeyDownMessage);
4764
4765        // which special key went down
4766        switch ( flavor )
4767        {
4768            case NX_KEYTYPE_EJECT:
4769
4770                //  Special key handlers:
4771                //
4772                //  Command = invoke macsbug
4773                //  Command+option = sleep now
4774                //  Command+option+control = shutdown now
4775                //  Control = logout dialog
4776
4777                if(  (evg->eventFlags & NX_COMMANDMASK)     &&
4778                    !(evg->eventFlags & NX_CONTROLMASK)     &&
4779                    !(evg->eventFlags & NX_SHIFTMASK)       &&
4780                    !(evg->eventFlags & NX_ALTERNATEMASK)       )
4781                {
4782                    // Post a power key event, Classic should pick this up and
4783                    // drop into MacsBug.
4784                    //
4785                    outData.compound.subType = NX_SUBTYPE_POWER_KEY;
4786                    postEvent(     NX_SYSDEFINED,
4787                    /* at */       &_cursorHelper.desktopLocation(),
4788                    /* atTime */   ts,
4789                    /* withData */ &outData,
4790                    /* sender */   sender,
4791                    /* extPID */   0,
4792                    /* processKEQ*/false);
4793                }
4794                else if(   (evg->eventFlags & NX_COMMANDMASK)   &&
4795                          !(evg->eventFlags & NX_CONTROLMASK)   &&
4796                          !(evg->eventFlags & NX_SHIFTMASK)     &&
4797                           (evg->eventFlags & NX_ALTERNATEMASK)     )
4798                {
4799                    //IOLog( "IOHIDSystem -- sleep now!\n" );
4800
4801                    // The Key release events may not get delivered
4802                    // to clients if they come late in sleep process. So,
4803                    // clear the flags before heading to sleep.
4804                    evg->eventFlags = 0;
4805                    // Post the sleep now event. Someone else will handle the actual call.
4806                    //
4807                    outData.compound.subType = NX_SUBTYPE_SLEEP_EVENT;
4808                    postEvent(     NX_SYSDEFINED,
4809                    /* at */       &_cursorHelper.desktopLocation(),
4810                    /* atTime */   ts,
4811                    /* withData */ &outData,
4812                    /* sender */   sender,
4813                    /* extPID */   0,
4814                    /* processKEQ*/false);
4815
4816                }
4817                else if(   (evg->eventFlags & NX_COMMANDMASK)   &&
4818                           (evg->eventFlags & NX_CONTROLMASK)   &&
4819                          !(evg->eventFlags & NX_SHIFTMASK)     &&
4820                           (evg->eventFlags & NX_ALTERNATEMASK)     )
4821                {
4822                    //IOLog( "IOHIDSystem -- shutdown now!\n" );
4823
4824                    // Post the shutdown now event. Someone else will handle the actual call.
4825                    //
4826                    outData.compound.subType = NX_SUBTYPE_SHUTDOWN_EVENT;
4827                    postEvent(     NX_SYSDEFINED,
4828                    /* at */       &_cursorHelper.desktopLocation(),
4829                    /* atTime */   ts,
4830                    /* withData */ &outData,
4831                    /* sender */   sender,
4832                    /* extPID */   0,
4833                    /* processKEQ*/false);
4834
4835                }
4836                else if(   (evg->eventFlags & NX_COMMANDMASK)   &&
4837                           (evg->eventFlags & NX_CONTROLMASK)   &&
4838                          !(evg->eventFlags & NX_SHIFTMASK)     &&
4839                          !(evg->eventFlags & NX_ALTERNATEMASK)     )
4840                {
4841                    // Restart now!
4842                    //IOLog( "IOHIDSystem -- Restart now!\n" );
4843
4844                    // Post the Restart now event. Someone else will handle the actual call.
4845                    //
4846                    outData.compound.subType = NX_SUBTYPE_RESTART_EVENT;
4847                    postEvent(     NX_SYSDEFINED,
4848                    /* at */       &_cursorHelper.desktopLocation(),
4849                    /* atTime */   ts,
4850                    /* withData */ &outData,
4851                    /* sender */   sender,
4852                    /* extPID */   0,
4853                    /* processKEQ*/false);
4854
4855                }
4856                else if(  !(evg->eventFlags & NX_COMMANDMASK)   &&
4857                           (evg->eventFlags & NX_CONTROLMASK)   &&
4858                          !(evg->eventFlags & NX_SHIFTMASK)     &&
4859                          !(evg->eventFlags & NX_ALTERNATEMASK)     )
4860                {
4861                    // Looks like we should put up the normal 'Power Key' dialog.
4862                    //
4863                    // Set the event flags to zero, because the system will not do the right
4864                    // thing if we don't zero this out (it will ignore the power key event
4865                    // we post, thinking that some modifiers are down).
4866                    //
4867                    evg->eventFlags = 0;
4868
4869                    // Post the power keydown event.
4870                    //
4871                    outData.compound.subType = NX_SUBTYPE_POWER_KEY;
4872                    postEvent(     NX_SYSDEFINED,
4873                    /* at */       &_cursorHelper.desktopLocation(),
4874                    /* atTime */   ts,
4875                    /* withData */ &outData,
4876                    /* sender */   sender,
4877                    /* extPID */   0,
4878                    /* processKEQ*/false);
4879
4880                }
4881                else
4882                {
4883                    // After all that checking, no modifiers are down, so let's pump up a
4884                    // system defined eject event. This way we can have anyone who's watching
4885                    // for this event (aka LoginWindow) route this event to the right target
4886                    // (aka AutoDiskMounter).
4887
4888                    //IOLog( "IOHIDSystem--Normal Eject action!\n" );
4889
4890                    // Post the eject keydown event.
4891                    //
4892                    outData.compound.subType = NX_SUBTYPE_EJECT_KEY;
4893                    postEvent(     NX_SYSDEFINED,
4894                    /* at */       &_cursorHelper.desktopLocation(),
4895                    /* atTime */   ts,
4896                    /* withData */ &outData,
4897                    /* sender */   sender,
4898                    /* extPID */   0,
4899                    /* processKEQ*/false);
4900
4901                }
4902                break;
4903
4904            case NX_POWER_KEY:
4905                // first issue a power key down event
4906                keyboardEventGated(eventType,
4907                                   flags,
4908                                   0x7f,
4909                                   0,
4910                                   0,
4911                                   0,
4912                                   0,
4913                                   0,
4914                                   0,
4915                                   ts,
4916                                   sender);
4917                // Now the special event
4918                outData.compound.subType = NX_SUBTYPE_POWER_KEY;
4919                postEvent(         NX_SYSDEFINED,
4920                    /* at */       &_cursorHelper.desktopLocation(),
4921                    /* atTime */   ts,
4922                    /* withData */ &outData,
4923                    /* sender */   sender,
4924                    /* extPID */   0,
4925                    /* processKEQ*/false);
4926                break;
4927        }
4928    }
4929    else if ( eventType == NX_KEYUP )
4930    {
4931        switch ( flavor )
4932        {
4933            case NX_POWER_KEY:
4934                keyboardEventGated(eventType,
4935                                   flags,
4936                                   0x7f,
4937                                   0,
4938                                   0,
4939                                   0,
4940                                   0,
4941                                   0,
4942                                   0,
4943                                   ts,
4944                                   sender);
4945                break;
4946        }
4947    }
4948    // if someone pases a sysdefined type in, then its ready to go already
4949    else if ( eventType == NX_SYSDEFINED )
4950    {
4951        outData.compound.subType = flavor;
4952        postEvent(         NX_SYSDEFINED,
4953            /* at */       &_cursorHelper.desktopLocation(),
4954            /* atTime */   ts,
4955            /* withData */ &outData,
4956            /* sender */   sender,
4957                    /* extPID */   0,
4958                    /* processKEQ*/false);
4959
4960    }
4961
4962    // post keydowns and key ups if this flavor should be posted
4963    // note, we dont want to do this for events of type NX_SYSDEFINED
4964    // we probably _should_ just check for keydowns and keyups here
4965    // but the smallest change was to just make sure we didnt do this for
4966    // the new type, which is NX_SYSDEFINED (used for sticky keys feature)
4967    if ( eventType != NX_SYSDEFINED )
4968    {
4969          if( (flags & SPECIALKEYS_MODIFIER_MASK)
4970            && (flavor == NX_POWER_KEY))
4971      {
4972        //Should modifier + POWER ever be dispatched?  Command-power
4973        //  is used to get into debugger and MacsBug
4974      }
4975      else
4976      {
4977            outData.compound.subType   = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
4978            outData.compound.misc.L[0] = (flavor << 16) | (eventType << 8) | repeat;
4979            outData.compound.misc.L[1] = guid & 0xffffffff;
4980            outData.compound.misc.L[2] = guid >> 32;
4981
4982            postEvent(             NX_SYSDEFINED,
4983                    /* at */       &_cursorHelper.desktopLocation(),
4984                    /* atTime */   ts,
4985                    /* withData */ &outData,
4986                    /* sender */   sender,
4987                    /* extPID */   0,
4988                    /* processKEQ*/false);
4989
4990          }
4991    }
4992
4993    if ( level != -1 )  // An interesting special key event occurred
4994    {
4995        evSpecialKeyMsg(        flavor,
4996            /* direction */ eventType,
4997            /* flags */     flags,
4998            /* level */     level);
4999    }
5000}
5001
5002/*
5003 * Update current event flags.  Restricted to keyboard flags only, this
5004 * method is used to silently update the flags state for keys which both
5005 * generate characters and flag changes.  The specs say we don't generate
5006 * a flags-changed event for such keys.  This method is also used to clear
5007 * the keyboard flags on a keyboard subsystem reset.
5008 */
5009void IOHIDSystem::_updateEventFlags(IOHIDSystem * self,
5010                                    unsigned      flags,
5011                                    OSObject *    sender,
5012                                    void *        refcon __unused)
5013{
5014    self->updateEventFlags(flags, sender);
5015}
5016
5017void IOHIDSystem::updateEventFlags(unsigned flags)
5018{
5019    updateEventFlags(flags, 0);
5020}
5021
5022void IOHIDSystem::updateEventFlags(unsigned flags, OSObject * sender)
5023{
5024    KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
5025
5026    if ( !keyboardEQElement )
5027        return;
5028
5029    bzero(keyboardEQElement, sizeof(KeyboardEQElement));
5030
5031    keyboardEQElement->action = IOHIDSystem::doUpdateEventFlags;
5032    keyboardEQElement->sender = sender;
5033    if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ
5034
5035    keyboardEQElement->event.flagsChanged.flags = flags;
5036
5037    KEYBOARD_EQ_LOCK;
5038    enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
5039    KEYBOARD_EQ_UNLOCK;
5040
5041    keyboardEQES->interruptOccurred(0, 0, 0);
5042}
5043
5044IOReturn IOHIDSystem::doUpdateEventFlags(IOHIDSystem *self, void * args)
5045                        /* IOCommandGate::Action */
5046{
5047    KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
5048
5049    OSObject * sender   = keyboardEQElement->sender;
5050    unsigned   flags    = keyboardEQElement->event.flagsChanged.flags;
5051
5052    self->updateEventFlagsGated(flags, sender);
5053
5054    return kIOReturnSuccess;
5055}
5056
5057void IOHIDSystem::updateEventFlagsGated(unsigned flags, OSObject * sender __unused)
5058{
5059    if ( eventsOpen ) {
5060        evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
5061                | (flags & KEYBOARD_FLAGSMASK);
5062
5063            // RY: Reset the clickTime as well on modifier
5064            // change to prevent double click from occuring
5065            nanoseconds_to_absolutetime(0, &clickTime);
5066        }
5067}
5068
5069//
5070// - _setButtonState:(int)buttons  atTime:(int)t
5071//  Update the button state.  Generate button events as needed
5072//
5073void IOHIDSystem::_setButtonState(int buttons,
5074                                  /* atTime */ AbsoluteTime ts,
5075                                  OSObject * sender)
5076{
5077    // *** HACK ALERT ***
5078    // Chache the sent button state and or it with the other button states.
5079    // This will prevent awkward behavior when two pointing devices are used
5080    // at the same time.
5081    CachedMouseEventStruct *cachedMouseEvent = NULL;
5082
5083    if ( cachedButtonStates ) {
5084        cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
5085
5086        if (cachedMouseEvent) {
5087            cachedMouseEvent->lastButtons = buttons;
5088        }
5089
5090        if (evg->buttons == buttons)
5091            return;
5092
5093        buttons = GetCachedMouseButtonStates(cachedButtonStates);
5094    }
5095    // *** END HACK ***
5096
5097    // Once again check if new button state differs
5098    if (evg->buttons == buttons)
5099        return;
5100
5101    if (_scMouseCanReset && _scCount) {
5102        log_scroll_state("Resetting _scCount due to click: %lld\n", ts);
5103        _scCount = 0;
5104    }
5105
5106    // Magic uber-mouse buttons changed event so we can get all of the buttons...
5107    NXEventData evData;
5108    unsigned long hwButtons, hwDelta;
5109
5110    /* I'd like to keep the event button mapping linear, so
5111        I have to "undo" the LB/RB mouse bit numbering funkiness
5112        before I pass the information down to the app. */
5113    /* Ideally this would all go away if we fixed EV_LB and EV_RB
5114        to be bits 0 and 1 */
5115    CONVERT_EV_TO_HW_BUTTONS(buttons, hwButtons);
5116    CONVERT_EV_TO_HW_DELTA((evg->buttons ^ buttons), hwDelta);
5117
5118    evData.compound.reserved = 0;
5119    evData.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
5120    evData.compound.misc.L[0] = hwDelta;
5121    evData.compound.misc.L[1] = hwButtons;
5122
5123    postEvent(  NX_SYSDEFINED,
5124                /* at */ &_cursorHelper.desktopLocation(),
5125                /* atTime */ ts,
5126                /* withData */ &evData,
5127                /* sender */    sender);
5128
5129    // End Magic uber-mouse buttons changed event
5130
5131    bzero(&evData, sizeof(NXEventData));
5132
5133    // vtn3: This will update the data structure for touch devices
5134    updateMouseEventForSender(sender, &evData);
5135
5136    // RY: Roll in the tablet info we got from absolutePointerEventGated
5137    // into a button event.  Prior to this we were sending null data to
5138    // post event.  This won't be much different as the only non-zero
5139    // contents should be the tablet area of the event.
5140    if (cachedMouseEvent ||
5141        (NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)))) {
5142        if (evData.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH)
5143            evData.mouse.subType = cachedMouseEvent->subType;
5144        evData.mouse.pressure = cachedMouseEvent->lastPressure;
5145
5146        if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT) {
5147            bcopy(&(cachedMouseEvent->tabletData), &(evData.mouse.tablet.point), sizeof(NXTabletPointData));
5148        }
5149        else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY) {
5150            bcopy(&(cachedMouseEvent->proximityData), &(evData.mouse.tablet.proximity), sizeof(NXTabletProximityData));
5151        }
5152    }
5153    evData.mouse.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8;
5154    evData.mouse.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8;
5155
5156    if ((evg->buttons & EV_LB) != (buttons & EV_LB)) {
5157        if (buttons & EV_LB) {
5158            postEvent(             NX_LMOUSEDOWN,
5159                                   /* at */       &_cursorHelper.desktopLocation(),
5160                                   /* atTime */   ts,
5161                                   /* withData */ &evData,
5162                                   /* sender */   sender);
5163        }
5164        else {
5165            postEvent(             NX_LMOUSEUP,
5166                                   /* at */       &_cursorHelper.desktopLocation(),
5167                                   /* atTime */   ts,
5168                                   /* withData */ &evData,
5169                                   /* sender */   sender);
5170        }
5171        // After entering initial up/down event, set up
5172        // coalescing state so drags will behave correctly
5173        evg->dontCoalesce = evg->dontWantCoalesce;
5174        if (evg->dontCoalesce)
5175            evg->eventFlags |= NX_NONCOALSESCEDMASK;
5176        else
5177            evg->eventFlags &= ~NX_NONCOALSESCEDMASK;
5178    }
5179
5180    if ((evg->buttons & EV_RB) != (buttons & EV_RB)) {
5181        if (buttons & EV_RB) {
5182            postEvent(             NX_RMOUSEDOWN,
5183                                   /* at */       &_cursorHelper.desktopLocation(),
5184                                   /* atTime */   ts,
5185                                   /* withData */ &evData,
5186                                   /* sender */   sender);
5187        }
5188        else {
5189            postEvent(             NX_RMOUSEUP,
5190                                   /* at */       &_cursorHelper.desktopLocation(),
5191                                   /* atTime */   ts,
5192                                   /* withData */ &evData,
5193                                   /* sender */   sender);
5194        }
5195    }
5196
5197    evg->buttons = buttons;
5198}
5199
5200//
5201//  Sets the cursor position (evg->cursorLoc) to the new
5202//  location.  The location is clipped against the cursor pin rectangle,
5203//  mouse moved/dragged events are generated using the given event mask,
5204//  and a mouse-exited event may be generated. The cursor image is
5205//  moved.
5206//  This should be run from a command gate action.
5207//
5208void IOHIDSystem::setCursorPosition(IOGPoint * newLoc, bool external, OSObject * sender)
5209{
5210    if ( eventsOpen == true )
5211    {
5212        clock_get_uptime(&_cursorEventLast);
5213        _cursorHelper.desktopLocationDelta().xValue() += (newLoc->x - _cursorHelper.desktopLocation().xValue());
5214        _cursorHelper.desktopLocationDelta().yValue() += (newLoc->y - _cursorHelper.desktopLocation().yValue());
5215        _cursorHelper.desktopLocation().fromIntFloor(newLoc->x, newLoc->y);
5216        _setCursorPosition(external, false, sender);
5217        _cursorMoveLast = _cursorEventLast;
5218        scheduleNextPeriodicEvent();
5219    }
5220}
5221
5222//
5223// This mechanism is used to update the cursor position, possibly generating
5224// messages to registered frame buffer devices and posting drag, tracking, and
5225// mouse motion events.
5226//
5227// This should be run from a command gate action.
5228// This can be called from setCursorPosition:(IOGPoint *)newLoc to set the
5229// position by a _IOSetParameterFromIntArray() call, directly from the absolute or
5230// relative pointer device routines, or on a timed event callback.
5231//
5232void IOHIDSystem::_setCursorPosition(bool external, bool proximityChange, OSObject * sender)
5233{
5234    bool cursorMoved = true;
5235    IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender,
5236                _cursorHelper.desktopLocation().xValue().as64(),
5237                _cursorHelper.desktopLocation().yValue().as64(), 0);
5238    IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender, proximityChange, external, 1);
5239    PROFILE_TRACE(9);
5240
5241    if (!screens) {
5242        return;
5243    }
5244
5245    if( OSSpinLockTry(&evg->cursorSema) == 0 ) { // host using shmem
5246        // try again later
5247        return;
5248    }
5249
5250    // Past here we hold the cursorSema lock.  Make sure the lock is
5251    // cleared before returning or the system will be wedged.
5252    if (cursorCoupled || external)
5253    {
5254        UInt32 newScreens = 0;
5255        SInt32 pinScreen = -1L;
5256        EvScreen *screen = (EvScreen *)evScreen;
5257
5258        if (cursorPinned) {
5259            _cursorHelper.desktopLocation().clipToRect(cursorPin);
5260        }
5261        else {
5262            /* Get mask of screens on which the cursor is present */
5263            for (int i = 0; i < screens; i++ ) {
5264                if (!screen[i].desktopBounds)
5265                    continue;
5266                if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
5267                    continue;
5268                if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
5269                    pinScreen = i;
5270                    newScreens |= (1 << i);
5271                }
5272            }
5273        }
5274
5275        if (newScreens == 0) {
5276            /* At this point cursor has gone off all screens,
5277               clip it to the closest screen. */
5278            IOFixedPoint64  aimLoc = _cursorHelper.desktopLocation();
5279            int64_t     dx;
5280            int64_t     dy;
5281            uint64_t    distance;
5282            uint64_t    bestDistance = -1ULL;
5283            for (int i = 0; i < screens; i++ ) {
5284                if (!screen[i].desktopBounds)
5285                    continue;
5286                if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
5287                    continue;
5288                IOFixedPoint64  pinnedLoc = aimLoc;
5289                pinnedLoc.clipToRect(*screen[i].desktopBounds);
5290                dx = (pinnedLoc.xValue() - aimLoc.xValue()).as64();
5291                dy = (pinnedLoc.yValue() - aimLoc.yValue()).as64();
5292                distance = dx * dx + dy * dy;
5293                if (distance <= bestDistance) {
5294                    bestDistance = distance;
5295                    _cursorHelper.desktopLocation() = pinnedLoc;
5296                }
5297            }
5298            IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender,
5299                        _cursorHelper.desktopLocation().xValue().as64(),
5300                        _cursorHelper.desktopLocation().yValue().as64(), 2);
5301
5302            /* regenerate mask for new position */
5303            for (int i = 0; i < screens; i++ ) {
5304                if (!screen[i].desktopBounds)
5305                    continue;
5306                if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
5307                    continue;
5308                if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
5309                    pinScreen = i;
5310                    newScreens |= (1 << i);
5311                }
5312            }
5313        }
5314
5315        /* Catch the no-move case */
5316        if ((_cursorHelper.desktopLocation().xValue().asFixed24x8() == evg->desktopCursorFixed.x) &&
5317            (_cursorHelper.desktopLocation().yValue().asFixed24x8() == evg->desktopCursorFixed.y) &&
5318            (proximityChange == 0) && (!_cursorHelper.desktopLocationDelta())) {
5319            cursorMoved = false;    // mouse moved, but cursor didn't
5320        }
5321        else {
5322            evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32();
5323            evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32();
5324            evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8();
5325            evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8();
5326            if (pinScreen >= 0) {
5327                _cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds);
5328            }
5329            else {
5330                _cursorHelper.updateScreenLocation(NULL, NULL);
5331            }
5332            evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8();
5333            evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8();
5334
5335            /* If cursor changed screens */
5336            if (newScreens != cursorScreens) {
5337                hideCursor();   /* hide cursor on old screens */
5338                cursorScreens = newScreens;
5339                if (pinScreen >= 0) {
5340                    cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds);
5341                    cursorPinScreen = pinScreen;
5342                    showCursor();
5343                }
5344            } else {
5345                /* cursor moved on same screens */
5346                moveCursor();
5347            }
5348        }
5349    }
5350    else {
5351        /* cursor uncoupled */
5352        _cursorHelper.desktopLocation().xValue().fromFixed24x8(evg->desktopCursorFixed.x);
5353        _cursorHelper.desktopLocation().yValue().fromFixed24x8(evg->desktopCursorFixed.y);
5354    }
5355
5356    AbsoluteTime    uptime;
5357    clock_get_uptime(&uptime);
5358
5359    _cursorLog(uptime);
5360
5361    /* See if anybody wants the mouse moved or dragged events */
5362    // Note: extPostEvent clears evg->movedMask as a hack to prevent these events
5363    // so any change here should check to make sure it does not break that hack
5364    if (evg->movedMask) {
5365        if      ((evg->movedMask & NX_LMOUSEDRAGGEDMASK) && (evg->buttons & EV_LB)) {
5366            _postMouseMoveEvent(NX_LMOUSEDRAGGED, uptime, sender);
5367        }
5368        else if ((evg->movedMask & NX_RMOUSEDRAGGEDMASK) && (evg->buttons & EV_RB)) {
5369            _postMouseMoveEvent(NX_RMOUSEDRAGGED, uptime, sender);
5370        }
5371        else if  (evg->movedMask & NX_MOUSEMOVEDMASK) {
5372            _postMouseMoveEvent(NX_MOUSEMOVED, uptime, sender);
5373        }
5374    }
5375
5376    /* check new cursor position for leaving evg->mouseRect */
5377    if (cursorMoved && evg->mouseRectValid && _cursorHelper.desktopLocation().inRect(evg->mouseRect))
5378    {
5379        if (evg->mouseRectValid)
5380        {
5381            postEvent(/* what */     NX_MOUSEEXITED,
5382                      /* at */       &_cursorHelper.desktopLocation(),
5383                      /* atTime */   uptime,
5384                      /* withData */ NULL,
5385                      /* sender */   sender);
5386            evg->mouseRectValid = 0;
5387        }
5388    }
5389    OSSpinLockUnlock(&evg->cursorSema);
5390    PROFILE_TRACE(10);
5391}
5392
5393void IOHIDSystem::_postMouseMoveEvent(int          what,
5394                                     AbsoluteTime  ts,
5395                                     OSObject *    sender)
5396{
5397    NXEventData data;
5398    CachedMouseEventStruct *cachedMouseEvent = 0;
5399    PROFILE_TRACE(11);
5400
5401    bzero( &data, sizeof(data) );
5402    data.mouseMove.dx = _cursorHelper.desktopLocationDelta().xValue().as32();
5403    data.mouseMove.dy = _cursorHelper.desktopLocationDelta().yValue().as32();
5404    data.mouseMove.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8;
5405    data.mouseMove.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8;
5406
5407    _cursorHelper.desktopLocationDelta() = IOFixedPoint64();
5408    _cursorLog(AbsoluteTime_to_scalar(&ts));
5409
5410    // vtn3: This will update the data structure for touch devices
5411    updateMouseMoveEventForSender(sender, &data);
5412
5413    // RY: Roll in the tablet info we got from absolutePointerEventGated
5414    // into the mouseMove event.
5415    if (sender && (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)))
5416    {
5417        if (data.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH)
5418            data.mouseMove.subType = cachedMouseEvent->subType;
5419        data.mouseMove.reserved1 = cachedMouseEvent->lastPressure;
5420
5421        if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY)
5422        {
5423            bcopy(&(cachedMouseEvent->proximityData), &(data.mouseMove.tablet.proximity), sizeof(NXTabletProximityData));
5424        }
5425        else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT)
5426        {
5427            bcopy(&(cachedMouseEvent->tabletData), &(data.mouseMove.tablet.point), sizeof(NXTabletPointData));
5428        }
5429    }
5430
5431    postEvent(what, &_cursorHelper.desktopLocation(), ts, &data, sender);
5432    PROFILE_TRACE(12);
5433}
5434
5435/**
5436 ** IOUserClient methods
5437 **/
5438
5439IOReturn IOHIDSystem::newUserClient(task_t         owningTask,
5440                    /* withToken */ void *         security_id,
5441                    /* ofType */    UInt32         type,
5442                    /* withProps*/  OSDictionary *  properties,
5443                    /* client */    IOUserClient ** handler)
5444{
5445    IOHIDCmdGateActionArgs args;
5446
5447    args.arg0 = &owningTask;
5448    args.arg1 = security_id;
5449    args.arg2 = &type;
5450    args.arg3 = properties;
5451    args.arg4 = handler;
5452
5453    return cmdGate->runAction((IOCommandGate::Action)doNewUserClient, &args);
5454}
5455
5456IOReturn IOHIDSystem::doNewUserClient(IOHIDSystem *self, void * args)
5457                        /* IOCommandGate::Action */
5458{
5459    task_t         owningTask   = *(task_t *) ((IOHIDCmdGateActionArgs *)args)->arg0;
5460    void *         security_id  = ((IOHIDCmdGateActionArgs *)args)->arg1;
5461    UInt32         type         = *(UInt32 *) ((IOHIDCmdGateActionArgs *)args)->arg2;
5462    OSDictionary * properties   = (OSDictionary *) ((IOHIDCmdGateActionArgs *)args)->arg3;
5463    IOUserClient ** handler     = (IOUserClient **) ((IOHIDCmdGateActionArgs *)args)->arg4;
5464
5465    return self->newUserClientGated(owningTask, security_id, type, properties, handler);
5466}
5467
5468IOReturn IOHIDSystem::newUserClientGated(task_t    owningTask,
5469                    /* withToken */ void *         security_id,
5470                    /* ofType */    UInt32         type,
5471                    /* withProps*/  OSDictionary *  properties,
5472                    /* client */    IOUserClient ** handler)
5473{
5474    IOUserClient * newConnect = 0;
5475    IOReturn  err = kIOReturnNoMemory;
5476
5477    do {
5478        if ( type == kIOHIDParamConnectType) {
5479            if ( paramConnect) {
5480                newConnect = paramConnect;
5481                newConnect->retain();
5482            }
5483            else if ( eventsOpen) {
5484                newConnect = new IOHIDParamUserClient;
5485            }
5486            else {
5487                err = kIOReturnNotOpen;
5488                continue;
5489            }
5490
5491        }
5492        else if ( type == kIOHIDServerConnectType) {
5493            newConnect = new IOHIDUserClient;
5494        }
5495        else if ( type == kIOHIDStackShotConnectType ) {
5496            newConnect = new IOHIDStackShotUserClient;
5497        }
5498        else if ( type == kIOHIDEventSystemConnectType ) {
5499            newConnect = new IOHIDEventSystemUserClient;
5500        }
5501        else {
5502            err = kIOReturnUnsupported;
5503        }
5504
5505        if ( !newConnect) {
5506            continue;
5507        }
5508
5509        // initialization is getting out of hand
5510
5511        if ( (newConnect != paramConnect) && (
5512                    (false == newConnect->initWithTask(owningTask, security_id, type, properties))
5513                    || (false == newConnect->setProperty(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue))
5514                    || (false == newConnect->attach( this ))
5515                    || (false == newConnect->start( this ))
5516                    || ((type == kIOHIDServerConnectType)
5517                        && (err = evOpen()))
5518                )) {
5519            newConnect->detach( this );
5520            newConnect->release();
5521            newConnect = 0;
5522            continue;
5523        }
5524        if ( type == kIOHIDParamConnectType)
5525            paramConnect = newConnect;
5526
5527        err = kIOReturnSuccess;
5528
5529    }
5530    while( false );
5531
5532#ifdef DEBUG
5533    int             pid = -1;
5534    proc_t          p = (proc_t)get_bsdtask_info(owningTask);
5535    pid = proc_pid(p);
5536    IOLog("%s (%d) %s returned %p\n", __func__, pid,
5537          type == kIOHIDParamConnectType ? "IOHIDParamUserClient" :
5538          type == kIOHIDServerConnectType ? "IOHIDUserClient" :
5539          type == kIOHIDStackShotConnectType ? "IOHIDStackShotUserClient" :
5540          type == kIOHIDEventSystemConnectType ? "IOHIDEventSystemUserClient" :
5541          "kIOReturnUnsupported",
5542          newConnect);
5543#endif
5544
5545    IOHID_DEBUG(kIOHIDDebugCode_NewUserClient, type, err, newConnect, 0);
5546    *handler = newConnect;
5547    return err;
5548}
5549
5550
5551IOReturn IOHIDSystem::setEventsEnable(void*p1,void*,void*,void*,void*,void*)
5552{                                                                    // IOMethod
5553    IOReturn ret;
5554
5555    if (mac_iokit_check_hid_control(kauth_cred_get()))
5556        return kIOReturnNotPermitted;
5557
5558    ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePre, p1);
5559    if ( ret == kIOReturnSuccess ) {
5560        // reset outside gated context
5561        _resetMouseParameters();
5562    }
5563    ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePost, p1);
5564
5565    return ret;
5566}
5567
5568IOReturn IOHIDSystem::doSetEventsEnablePre(IOHIDSystem *self, void *p1)
5569                        /* IOCommandGate::Action */
5570{
5571    return self->setEventsEnablePreGated(p1);
5572}
5573
5574IOReturn IOHIDSystem::setEventsEnablePreGated(void*p1)
5575{
5576    bool enable = (bool)p1;
5577
5578    if( enable) {
5579        while ( evStateChanging )
5580            cmdGate->commandSleep(&evStateChanging);
5581
5582        evStateChanging = true;
5583        attachDefaultEventSources();
5584    }
5585    return( kIOReturnSuccess);
5586}
5587
5588IOReturn IOHIDSystem::doSetEventsEnablePost(IOHIDSystem *self, void *p1)
5589                        /* IOCommandGate::Action */
5590{
5591    return self->setEventsEnablePostGated(p1);
5592}
5593
5594IOReturn IOHIDSystem::setEventsEnablePostGated(void*p1)
5595{
5596    bool enable = (bool)p1;
5597
5598    if( enable) {
5599        evStateChanging = false;
5600        cmdGate->commandWakeup(&evStateChanging);
5601    }
5602    return( kIOReturnSuccess);
5603}
5604
5605
5606IOReturn IOHIDSystem::setCursorEnable(void*p1,void*,void*,void*,void*,void*)
5607{                                                                    // IOMethod
5608    if (mac_iokit_check_hid_control(kauth_cred_get()))
5609        return kIOReturnNotPermitted;
5610
5611    return cmdGate->runAction((IOCommandGate::Action)doSetCursorEnable, p1);
5612
5613}
5614
5615IOReturn IOHIDSystem::doSetCursorEnable(IOHIDSystem *self, void * arg0)
5616                        /* IOCommandGate::Action */
5617{
5618    return self->setCursorEnableGated(arg0);
5619}
5620
5621IOReturn IOHIDSystem::setCursorEnableGated(void* p1)
5622{
5623    bool        enable = (bool)(intptr_t)p1;
5624
5625    if ( !eventsOpen ) {
5626        return kIOReturnNotOpen;
5627    }
5628
5629    if( !screens) {
5630        return kIOReturnNoDevice;
5631    }
5632
5633    if( enable ) {
5634        if( cursorStarted) {
5635            hideCursor();
5636            cursorEnabled = resetCursor();
5637            showCursor();
5638        }
5639        else {
5640            cursorEnabled = startCursor();
5641        }
5642    }
5643    else {
5644        cursorEnabled = enable;
5645    }
5646
5647    if (cursorCoupled != cursorEnabled) {
5648        _periodicEventNext = UINT64_MAX;
5649        _cursorMoveDelta = 0;
5650        _cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
5651        _cursorHelper.clearEventCounts();
5652        _cursorLogTimed();
5653        scheduleNextPeriodicEvent();
5654        cursorCoupled = cursorEnabled;
5655    }
5656
5657    return kIOReturnSuccess;
5658}
5659
5660IOReturn IOHIDSystem::extSetBounds( IOGBounds * bounds )
5661{
5662    if (mac_iokit_check_hid_control(kauth_cred_get()))
5663        return kIOReturnNotPermitted;
5664
5665    if( bounds->minx != bounds->maxx) {
5666        cursorPin = *bounds;
5667        cursorPinned = true;
5668    } else
5669        cursorPinned = false;
5670
5671    return( kIOReturnSuccess );
5672}
5673
5674IOReturn IOHIDSystem::extPostEvent(void*p1,void*p2,void*,void*,void*,void*)
5675{                                                                    // IOMethod
5676    AbsoluteTime    ts;
5677
5678    clock_get_uptime(&ts);
5679
5680    return cmdGate->runAction((IOCommandGate::Action)doExtPostEvent, p1, p2, &ts);
5681}
5682
5683IOReturn IOHIDSystem::doExtPostEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2, void * arg3 __unused)
5684                        /* IOCommandGate::Action */
5685{
5686    return self->extPostEventGated(arg0, arg1, arg2);
5687}
5688
5689IOReturn IOHIDSystem::extPostEventGated(void *p1,void *p2 __unused, void *p3)
5690{
5691    struct evioLLEvent * event      = (struct evioLLEvent *)p1;
5692    bool        isMoveOrDragEvent   = false;
5693    bool        isSeized            = false;
5694    int         oldMovedMask        = 0;
5695    UInt32      buttonState         = 0;
5696    UInt32      newFlags            = 0;
5697    AbsoluteTime ts                 = *(AbsoluteTime *)p3;
5698    CachedMouseEventStruct *cachedMouseEvent = NULL;
5699    UInt32      typeMask            = EventCodeMask(event->type);
5700
5701    // rdar://problem/8689199
5702    int         extPID = proc_selfpid();
5703
5704    IOHID_DEBUG(kIOHIDDebugCode_ExtPostEvent, event->type, *(UInt32*)&(event->location), event->setFlags, event->flags);
5705
5706
5707    if (event->type != NX_NULLEVENT && mac_iokit_check_hid_control(kauth_cred_get()))
5708        return kIOReturnNotPermitted;
5709
5710    if ( eventsOpen == false )
5711        return kIOReturnNotOpen;
5712
5713    if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline, false)) {
5714        if (typeMask & NX_WAKEMASK) {
5715            TICKLE_DISPLAY(event->type);
5716        }
5717        return kIOReturnSuccess;
5718    }
5719
5720    if (!DISPLAY_IS_ENABLED) {
5721#if !WAKE_DISPLAY_ON_MOVEMENT
5722        if ( (typeMask & NX_WAKEMASK) ||
5723           ((typeMask & MOVEDEVENTMASK) && (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0)) )
5724#endif
5725        {
5726            TICKLE_DISPLAY(event->type);
5727        }
5728        return kIOReturnSuccess;
5729    }
5730
5731    TICKLE_DISPLAY(event->type);
5732
5733    // used in set cursor below
5734    if (typeMask & MOVEDEVENTMASK)
5735    {
5736        isMoveOrDragEvent = true;
5737
5738        // We have mouse move event without a specified pressure value and an embedded tablet event
5739        // We need to scale the tablet pressure to fit in mouseMove pressure
5740        if ((event->data.mouseMove.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouseMove.reserved1 == 0))
5741        {
5742            event->data.mouseMove.reserved1 = ScalePressure(event->data.mouseMove.tablet.point.pressure);
5743        }
5744    }
5745    // We have mouse event without a specified pressure value and an embedded tablet event
5746    // We need to scale the tablet pressure to fit in mouse pressure
5747    else if ((typeMask & MOUSEEVENTMASK) &&
5748            (event->data.mouse.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouse.pressure == 0))
5749    {
5750        event->data.mouse.pressure = ScalePressure(event->data.mouse.tablet.point.pressure);
5751    }
5752
5753    if( event->setCursor)
5754    {
5755        // hack: clear evg->movedMask so setCursorPosition will not post
5756        // mouse moved events if this event is itself a mouse move event
5757        // this will prevent double events
5758        if (isMoveOrDragEvent)
5759        {
5760            oldMovedMask = evg->movedMask;
5761            evg->movedMask = 0;
5762        }
5763
5764        if (( event->type == NX_MOUSEMOVED ) &&
5765            ( event->setCursor & kIOHIDSetRelativeCursorPosition ))
5766        {
5767            IOFixedPoint32 move;
5768            move.x = (event->data.mouseMove.dx * 256);
5769            move.y = (event->data.mouseMove.dy * 256);
5770            _cursorHelper.desktopLocation() += move;
5771            _cursorHelper.desktopLocationDelta() += move;
5772
5773            _cursorLog(AbsoluteTime_to_scalar(&ts));
5774
5775            clock_get_uptime(&_cursorEventLast);
5776            _setCursorPosition();
5777            _cursorMoveLast = _cursorEventLast;
5778            // scheduleNextPeriodicEvent() happens at the end.
5779        }
5780        else if ( event->setCursor & kIOHIDSetCursorPosition )
5781        {
5782            setCursorPosition(&event->location, false);
5783        }
5784
5785        // other side of hack
5786        if (isMoveOrDragEvent)
5787            evg->movedMask = oldMovedMask;
5788    }
5789    // RY: This event is not moving the cursor, but we should
5790    // still determine if we need to click the location
5791    else
5792    {
5793        UInt32 newScreens = 0;
5794        EvScreen *screen = (EvScreen *)evScreen;
5795
5796        if (!cursorPinned) {
5797            /* Get mask of screens on which the cursor is present */
5798            for (int i = 0; i < screens; i++ ) {
5799                if (!screen[i].desktopBounds)
5800                    continue;
5801                if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
5802                    continue;
5803                if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
5804                    newScreens |= (1 << i);
5805                }
5806            }
5807        }
5808
5809        if (newScreens == 0)
5810        {
5811            /* At this point cursor has gone off all screens,
5812                    just clip it to one of the previous screens. */
5813            event->location.x = (event->location.x < cursorPin.minx) ?
5814                cursorPin.minx : ((event->location.x > cursorPin.maxx) ?
5815                cursorPin.maxx : event->location.x);
5816            event->location.y = (event->location.y < cursorPin.miny) ?
5817                cursorPin.miny : ((event->location.y > cursorPin.maxy) ?
5818                cursorPin.maxy : event->location.y);
5819        }
5820    }
5821
5822    if ((typeMask & (NX_LMOUSEDOWNMASK | NX_RMOUSEDOWNMASK | NX_LMOUSEUPMASK | NX_RMOUSEUPMASK)) ||
5823        ((event->type == NX_SYSDEFINED) && (event->data.compound.subType == NX_SUBTYPE_AUX_MOUSE_BUTTONS)))
5824    {
5825        cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0);
5826        if (cachedMouseEvent)
5827        {
5828            buttonState = cachedMouseEvent->lastButtons;
5829            switch ( event->type )
5830            {
5831                case NX_LMOUSEDOWN:
5832                    buttonState |= EV_LB;
5833                    break;
5834                case NX_RMOUSEDOWN:
5835                    buttonState |= EV_RB;
5836                    break;
5837                case NX_LMOUSEUP:
5838                    buttonState &= ~EV_LB;
5839                    break;
5840                case NX_RMOUSEUP:
5841                    buttonState &= ~EV_RB;
5842                    break;
5843                case NX_SYSDEFINED:
5844                    CONVERT_HW_TO_WV_BUTTONS(event->data.compound.misc.L[1], buttonState);
5845            }
5846            cachedMouseEvent->lastButtons = buttonState;
5847
5848            evg->buttons = GetCachedMouseButtonStates(cachedButtonStates);
5849        }
5850    }
5851
5852    if( event->setFlags & kIOHIDSetGlobalEventFlags)
5853    {
5854        newFlags = evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
5855                        | (event->flags & KEYBOARD_FLAGSMASK);
5856    }
5857
5858    if ( event->setFlags & kIOHIDPostHIDManagerEvent )
5859    {
5860        if ((typeMask & (MOUSEEVENTMASK | MOVEDEVENTMASK | NX_SCROLLWHEELMOVEDMASK)) &&
5861            (_hidPointingDevice || (_hidPointingDevice = IOHIDPointingDevice::newPointingDeviceAndStart(this, 8, 400, true, 2))))
5862        {
5863            SInt32  dx = 0;
5864            SInt32  dy = 0;
5865            SInt32  wheel = 0;
5866            buttonState = 0;
5867
5868            if (typeMask & MOVEDEVENTMASK)
5869            {
5870                dx = event->data.mouseMove.dx;
5871                dy = event->data.mouseMove.dy;
5872            }
5873            else if ( event->type == NX_SCROLLWHEELMOVED )
5874            {
5875                wheel = event->data.scrollWheel.deltaAxis1;
5876            }
5877
5878            // Button state should have already been taken care of by above.
5879            if (cachedMouseEvent ||
5880                (NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0))))
5881                CONVERT_EV_TO_HW_BUTTONS((cachedMouseEvent->lastButtons), buttonState);
5882
5883            _hidPointingDevice->postMouseEvent(buttonState, dx, dy, wheel);
5884            isSeized |= _hidPointingDevice->isSeized();
5885        }
5886
5887        if ((typeMask & (NX_KEYDOWNMASK | NX_KEYUPMASK | NX_FLAGSCHANGEDMASK)) &&
5888            (_hidKeyboardDevice || (_hidKeyboardDevice = IOHIDKeyboardDevice::newKeyboardDeviceAndStart(this, 1))))
5889        {
5890            _hidKeyboardDevice->postFlagKeyboardEvent(newFlags & KEYBOARD_FLAGSMASK);
5891
5892            if ((event->type != NX_FLAGSCHANGED) && (event->data.key.repeat == 0))
5893            {
5894                _hidKeyboardDevice->postKeyboardEvent(event->data.key.keyCode, (event->type == NX_KEYDOWN));
5895            }
5896
5897            isSeized |= _hidKeyboardDevice->isSeized();
5898        }
5899    }
5900
5901    if ( !isSeized )
5902    {
5903        postEvent(             event->type,
5904                /* at */       &_cursorHelper.desktopLocation(),
5905                /* atTime */   ts,
5906                /* withData */ &event->data,
5907                /* sender */   0,
5908                /* extPID */   extPID);
5909    }
5910
5911    scheduleNextPeriodicEvent();
5912
5913    return kIOReturnSuccess;
5914}
5915
5916
5917IOReturn IOHIDSystem::extSetMouseLocation(void*p1,void*p2,void*,void*,void*,void*)
5918{                                                                    // IOMethod
5919    if (mac_iokit_check_hid_control(kauth_cred_get()))
5920        return kIOReturnNotPermitted;
5921    if ((sizeof(int32_t)*3) != (intptr_t)p2) {
5922        IOLog("IOHIDSystem::extSetMouseLocation called with inappropriate data size: %d\n", (int)(intptr_t)p2);
5923        return kIOReturnBadArgument;
5924    }
5925
5926    return cmdGate->runAction((IOCommandGate::Action)doExtSetMouseLocation, p1);
5927}
5928
5929IOReturn IOHIDSystem::doExtSetMouseLocation(IOHIDSystem *self, void * arg0)
5930                        /* IOCommandGate::Action */
5931{
5932    return self->extSetMouseLocationGated(arg0);
5933}
5934
5935IOReturn IOHIDSystem::extSetMouseLocationGated(void *p1)
5936{
5937    IOFixedPoint32 * loc = (IOFixedPoint32 *)p1;
5938
5939    IOHID_DEBUG(kIOHIDDebugCode_ExtSetLocation, loc ? loc->x : 0, loc ? loc->y : 0, loc, 0);
5940
5941    //    setCursorPosition(loc, true);
5942    if ( eventsOpen == true )
5943    {
5944        _cursorHelper.desktopLocationDelta() += *loc;
5945        _cursorHelper.desktopLocationDelta() -= _cursorHelper.desktopLocation();
5946        _cursorHelper.desktopLocation() = *loc;
5947        _setCursorPosition(true);
5948    }
5949
5950    return kIOReturnSuccess;
5951}
5952
5953IOReturn IOHIDSystem::extGetStateForSelector(void*p1,void*p2,void*,void*,void*,void*)
5954{                                                                    // IOMethod
5955    return cmdGate->runAction((IOCommandGate::Action)doExtGetStateForSelector, p1, p2);
5956}
5957
5958IOReturn IOHIDSystem::extSetStateForSelector(void*p1,void*p2,void*,void*,void*,void*)
5959{                                                                    // IOMethod
5960    if (mac_iokit_check_hid_control(kauth_cred_get()))
5961        return kIOReturnNotPermitted;
5962
5963    return cmdGate->runAction((IOCommandGate::Action)doExtSetStateForSelector, p1, p2);
5964}
5965
5966IOReturn IOHIDSystem::doExtGetStateForSelector(IOHIDSystem *self, void *p1, void *p2)
5967/* IOCommandGate::Action */
5968{
5969    IOReturn result = kIOReturnSuccess;
5970    unsigned int selector = (uintptr_t)p1;
5971    unsigned int *state_O = (unsigned int*)p2;
5972    switch (selector) {
5973        case kIOHIDCapsLockState:
5974            result = self->getCapsLockState(state_O);
5975            break;
5976
5977        case kIOHIDNumLockState:
5978            result = self->getNumLockState(state_O);
5979            break;
5980
5981        case kIOHIDActivityUserIdle:
5982            *state_O = self->_privateData->hidActivityIdle ? 1 : 0;
5983            break;
5984
5985        case kIOHIDActivityDisplayOn:
5986            *state_O = self->displayState & IOPMDeviceUsable ? 1 : 0;
5987            break;
5988
5989        default:
5990            IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector);
5991            result = kIOReturnBadArgument;
5992            break;
5993    }
5994    return result;
5995}
5996
5997IOReturn IOHIDSystem::doExtSetStateForSelector(IOHIDSystem *self, void *p1, void *p2)
5998/* IOCommandGate::Action */
5999{
6000    IOReturn result = kIOReturnSuccess;
6001    unsigned int selector = (uintptr_t)p1;
6002    unsigned int state_I = (uintptr_t)p2;
6003
6004    switch (selector) {
6005        case kIOHIDCapsLockState:
6006            result = self->setCapsLockState(state_I);
6007            break;
6008
6009        case kIOHIDNumLockState:
6010            result = self->setNumLockState(state_I);
6011            break;
6012
6013        case kIOHIDActivityUserIdle:    // not settable
6014        case kIOHIDActivityDisplayOn:   // not settable
6015        default:
6016            IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector);
6017            result = kIOReturnBadArgument;
6018            break;
6019
6020    }
6021    return result;
6022}
6023
6024IOReturn IOHIDSystem::getCapsLockState(unsigned int *state_O)
6025{
6026    IOReturn retVal = kIOReturnNoDevice;
6027    *state_O = false;
6028    OSIterator *itr = getProviderIterator();
6029    if (itr) {
6030        bool done = false;
6031        while (!done) {
6032            OSObject *provider;
6033            while (!done && (NULL != (provider = itr->getNextObject()))) {
6034                IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
6035                if (keyboard) {
6036                    retVal = kIOReturnSuccess;
6037                    if (keyboard->alphaLock()) {
6038                        *state_O = true;
6039                        done = true;
6040                    }
6041                }
6042            }
6043            if (itr->isValid()) {
6044                done = true;
6045            }
6046            else {
6047                itr->reset();
6048            }
6049        }
6050        itr->release();
6051    }
6052    return retVal;
6053}
6054
6055IOReturn IOHIDSystem::setCapsLockState(unsigned int state_I)
6056{
6057    IOReturn retVal = kIOReturnNoDevice;
6058    OSIterator *itr = getProviderIterator();
6059    if (itr) {
6060        bool done = false;
6061        while (!done) {
6062            OSObject *provider;
6063            while (!done && (NULL != (provider = itr->getNextObject()))) {
6064                IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
6065                if (keyboard) {
6066                    if ((state_I && !keyboard->alphaLock()) || (!state_I && keyboard->alphaLock())) {
6067                        AbsoluteTime timeStamp;
6068                        UInt32 opts = (1<<31) /* kDelayedOption */;
6069                        clock_get_uptime(&timeStamp);
6070
6071                        keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 1, opts);
6072                        keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 0, opts);
6073                    }
6074                    retVal = kIOReturnSuccess;
6075                }
6076            }
6077            if (itr->isValid()) {
6078                done = true;
6079            }
6080            else {
6081                itr->reset();
6082            }
6083        }
6084        itr->release();
6085    }
6086    return retVal;
6087}
6088
6089IOReturn IOHIDSystem::getNumLockState(unsigned int *state_O)
6090{
6091    IOReturn retVal = kIOReturnNoDevice;
6092    *state_O = false;
6093    OSIterator *itr = getProviderIterator();
6094    if (itr) {
6095        bool done = false;
6096        while (!done) {
6097            OSObject *provider;
6098            while (!done && (NULL != (provider = itr->getNextObject()))) {
6099                IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
6100                if (keyboard) {
6101                    retVal = kIOReturnSuccess;
6102                    if (keyboard->numLock()) {
6103                        *state_O = true;
6104                        done = true;
6105                    }
6106                }
6107            }
6108            if (itr->isValid()) {
6109                done = true;
6110            }
6111            else {
6112                itr->reset();
6113            }
6114        }
6115        itr->release();
6116    }
6117    return retVal;
6118}
6119
6120IOReturn IOHIDSystem::setNumLockState(unsigned int state_I)
6121{
6122    IOReturn retVal = kIOReturnNoDevice;
6123    OSIterator *itr = getProviderIterator();
6124    if (itr) {
6125        bool done = false;
6126        while (!done) {
6127            OSObject *provider;
6128            while (!done && (NULL != (provider = itr->getNextObject()))) {
6129                IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
6130                if (keyboard) {
6131                    if ((state_I && !keyboard->numLock()) || (!state_I && keyboard->numLock())) {
6132                        AbsoluteTime timeStamp;
6133                        UInt32 opts = 0;
6134                        clock_get_uptime(&timeStamp);
6135
6136                        keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 1, opts);
6137                        keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 0, opts);
6138                    }
6139                    retVal = kIOReturnSuccess;
6140                }
6141            }
6142            if (itr->isValid()) {
6143                done = true;
6144            }
6145            else {
6146                itr->reset();
6147            }
6148        }
6149        itr->release();
6150    }
6151    return retVal;
6152}
6153
6154IOReturn IOHIDSystem::extGetButtonEventNum(void*p1,void*p2,void*,void*,void*,void*)
6155{                                                                   // IOMethod
6156    return cmdGate->runAction((IOCommandGate::Action)doExtGetButtonEventNum, p1, p2);
6157}
6158
6159IOReturn IOHIDSystem::doExtGetButtonEventNum(IOHIDSystem *self, void * arg0, void * arg1)
6160                        /* IOCommandGate::Action */
6161{
6162    return self->extGetButtonEventNumGated(arg0, arg1);
6163}
6164
6165IOReturn IOHIDSystem::extGetButtonEventNumGated(void *p1, void* p2)
6166{
6167    NXMouseButton button   = (NXMouseButton)(uintptr_t)p1;
6168    int *         eventNum = (int *)p2;
6169    IOReturn      err      = kIOReturnSuccess;
6170
6171    switch( button) {
6172    case NX_LeftButton:
6173            *eventNum = leftENum;
6174        break;
6175    case NX_RightButton:
6176            *eventNum = rightENum;
6177        break;
6178    default:
6179        err = kIOReturnBadArgument;
6180    }
6181
6182    return err;
6183}
6184
6185void IOHIDSystem::makeNumberParamProperty( OSDictionary * dict, const char * key,
6186                            unsigned long long number, unsigned int bits )
6187{
6188    OSNumber *  numberRef;
6189    numberRef = OSNumber::withNumber(number, bits);
6190
6191    if( numberRef) {
6192        dict->setObject( key, numberRef);
6193        numberRef->release();
6194    }
6195}
6196
6197void IOHIDSystem::makeInt32ArrayParamProperty( OSDictionary * dict, const char * key,
6198                            UInt32 * intArray, unsigned int count )
6199{
6200    OSArray *   array;
6201    OSNumber *  number;
6202
6203    array = OSArray::withCapacity(count);
6204
6205    if ( !array )
6206        return;
6207
6208    for (unsigned i=0; i<count; i++)
6209    {
6210        number = OSNumber::withNumber(intArray[i], sizeof(UInt32) << 3);
6211        if (number)
6212        {
6213            array->setObject(number);
6214            number->release();
6215        }
6216    }
6217
6218    dict->setObject( key, array);
6219    array->release();
6220}
6221
6222void IOHIDSystem::createParameters( void )
6223{
6224    UInt64  nano;
6225    IOFixed fixed;
6226    UInt32  int32;
6227
6228    savedParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
6229
6230    nano = EV_DCLICKTIME;
6231    makeNumberParamProperty( savedParameters, kIOHIDClickTimeKey,
6232                nano, 64 );
6233
6234    UInt32  tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y};
6235    makeInt32ArrayParamProperty( savedParameters, kIOHIDClickSpaceKey,
6236                tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) );
6237
6238    nano = EV_DEFAULTKEYREPEAT;
6239    makeNumberParamProperty( savedParameters, kIOHIDKeyRepeatKey,
6240                nano, 64 );
6241    nano = EV_DEFAULTINITIALREPEAT;
6242    makeNumberParamProperty( savedParameters, kIOHIDInitialKeyRepeatKey,
6243                nano, 64 );
6244
6245    fixed = EV_DEFAULTPOINTERACCELLEVEL;
6246    makeNumberParamProperty( savedParameters, kIOHIDPointerAccelerationKey,
6247                fixed, sizeof(fixed) << 3);
6248
6249    fixed = EV_DEFAULTSCROLLACCELLEVEL;
6250    makeNumberParamProperty( savedParameters, kIOHIDScrollAccelerationKey,
6251                fixed, sizeof(fixed) << 3);
6252
6253    fixed = kIOHIDButtonMode_EnableRightClick;
6254    makeNumberParamProperty( savedParameters, kIOHIDPointerButtonMode,
6255                fixed, sizeof(fixed) << 3);
6256
6257    // set eject delay properties
6258    int32 = kEjectF12DelayMS;
6259    makeNumberParamProperty( savedParameters, kIOHIDF12EjectDelayKey,
6260                            int32, 32 );
6261    int32 = kEjectKeyDelayMS;
6262    makeNumberParamProperty( savedParameters, kIOHIDKeyboardEjectDelay,
6263                            int32, 32 );
6264
6265    // set slow keys delay property
6266    int32 = 0;
6267    makeNumberParamProperty( savedParameters, kIOHIDSlowKeysDelayKey,
6268                int32, 32 );
6269
6270    // set disabled property
6271    int32 = 0; // not disabled
6272    makeNumberParamProperty( savedParameters, kIOHIDStickyKeysDisabledKey,
6273                int32, 32 );
6274
6275    // set on/off property
6276    int32 = 0; // off
6277    makeNumberParamProperty( savedParameters, kIOHIDStickyKeysOnKey,
6278                int32, 32 );
6279
6280    // set shift toggles property
6281    int32 = 0; // off, shift does not toggle
6282    makeNumberParamProperty( savedParameters, kIOHIDStickyKeysShiftTogglesKey,
6283                int32, 32 );
6284
6285    // set option toggles property
6286    int32 = 0; // off, option does not toggle
6287    makeNumberParamProperty( savedParameters, kIOHIDMouseKeysOptionTogglesKey,
6288                int32, 32 );
6289
6290    int32 = 0;
6291    makeNumberParamProperty( savedParameters, kIOHIDFKeyModeKey,
6292                            int32, 32 );
6293
6294    setProperty( kIOHIDParametersKey, savedParameters );
6295    savedParameters->release();
6296
6297    // RY: Set up idleTimeSerializer.  This should generate the
6298    // current idle time when requested.
6299    OSSerializer * idleTimeSerializer = OSSerializer::forTarget(this, IOHIDSystem::_idleTimeSerializerCallback);
6300
6301    if (idleTimeSerializer)
6302    {
6303        setProperty( kIOHIDIdleTimeKey, idleTimeSerializer);
6304        idleTimeSerializer->release();
6305    }
6306
6307#if 0
6308    OSSerializer * displaySerializer = OSSerializer::forTarget(this, IOHIDSystem::_displaySerializerCallback);
6309
6310    if (displaySerializer)
6311    {
6312        setProperty("DisplayState", displaySerializer);
6313        displaySerializer->release();
6314    }
6315#endif
6316}
6317
6318bool IOHIDSystem::_idleTimeSerializerCallback(void * target, void * ref __unused, OSSerialize *s)
6319{
6320    IOHIDSystem *   self = (IOHIDSystem *) target;
6321    AbsoluteTime    currentTime;
6322    OSNumber *      number;
6323    UInt64          idleTimeNano = 0;
6324    bool            retValue = false;
6325
6326    if( self->eventsOpen )
6327    {
6328        clock_get_uptime( &currentTime);
6329        SUB_ABSOLUTETIME( &currentTime, &(self->lastUndimEvent));
6330        absolutetime_to_nanoseconds( currentTime, &idleTimeNano);
6331    }
6332
6333    number = OSNumber::withNumber(idleTimeNano, 64);
6334    if (number)
6335    {
6336        retValue = number->serialize( s );
6337        number->release();
6338    }
6339
6340    return retValue;
6341}
6342
6343bool IOHIDSystem::_displaySerializerCallback(void * target, void * ref __unused, OSSerialize *s)
6344{
6345    IOHIDSystem     *self = (IOHIDSystem *) target;
6346    bool            retValue = false;
6347    OSDictionary    *mainDict = OSDictionary::withCapacity(4);
6348    require(mainDict, exit_early);
6349
6350#define IfNotNullAddNumToDictWithKey(x,y, w,z) \
6351    if (x) { \
6352        OSNumber *num = NULL; \
6353        num = OSNumber::withNumber(y, 8*sizeof(y)); \
6354        if (num) { \
6355            w->setObject(z, num); \
6356            num->release(); \
6357        } \
6358    }
6359
6360    for(int i = 0; i < self->screens; i++) {
6361        EvScreen &esp = ((EvScreen*)(self->evScreen))[i];
6362        OSDictionary    *thisDisplay = OSDictionary::withCapacity(4);
6363        char            key[256];
6364
6365        require(thisDisplay, next_display);
6366        snprintf(key, sizeof(key), "%d", i);
6367        mainDict->setObject(key, thisDisplay);
6368
6369        IfNotNullAddNumToDictWithKey(esp.instance, esp.instance->getRegistryEntryID(), thisDisplay, "io_fb_id");
6370        IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->minx, thisDisplay, "disp_min_x");
6371        IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxx, thisDisplay, "disp_max_x");
6372        IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->miny, thisDisplay, "disp_min_y");
6373        IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxy, thisDisplay, "disp_max_y");
6374        IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->minx, thisDisplay, "desk_min_x");
6375        IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxx, thisDisplay, "desk_max_x");
6376        IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->miny, thisDisplay, "desk_min_y");
6377        IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxy, thisDisplay, "desk_max_y");
6378        IfNotNullAddNumToDictWithKey(esp.creator_pid, esp.creator_pid, thisDisplay, "creator_pid");
6379
6380    next_display:
6381        OSSafeReleaseNULL(thisDisplay);
6382    }
6383
6384    {   // safety scoping
6385        OSDictionary    *workSpaceDict = OSDictionary::withCapacity(4);
6386        IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.minx, workSpaceDict, "minx");
6387        IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.miny, workSpaceDict, "miny");
6388        IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxx, workSpaceDict, "maxx");
6389        IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxy, workSpaceDict, "maxy");
6390        mainDict->setObject("workspace", workSpaceDict ? (OSObject*)workSpaceDict : (OSObject*)kOSBooleanFalse);
6391        OSSafeReleaseNULL(workSpaceDict);
6392    }
6393
6394    {   // safety scoping
6395        OSDictionary    *cursorPinDict = OSDictionary::withCapacity(4);
6396        IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.minx, cursorPinDict, "minx");
6397        IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.miny, cursorPinDict, "miny");
6398        IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxx, cursorPinDict, "maxx");
6399        IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxy, cursorPinDict, "maxy");
6400        mainDict->setObject("cursorPin", cursorPinDict ? (OSObject*)cursorPinDict : (OSObject*)kOSBooleanFalse);
6401        OSSafeReleaseNULL(cursorPinDict);
6402    }
6403
6404    retValue = mainDict->serialize( s );
6405
6406exit_early:
6407    OSSafeReleaseNULL(mainDict);
6408    return retValue;
6409}
6410
6411IOReturn IOHIDSystem::setProperties( OSObject * properties )
6412{
6413    OSDictionary *  dict;
6414    IOReturn        err = kIOReturnSuccess;
6415    IOReturn        ret;
6416
6417    dict = OSDynamicCast( OSDictionary, properties );
6418    if( dict) {
6419        if (dict->getObject(kIOHIDUseKeyswitchKey) &&
6420            ( IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator) != kIOReturnSuccess)) {
6421            dict->removeObject(kIOHIDUseKeyswitchKey);
6422        }
6423        ret = setParamProperties( dict );
6424    }
6425    else
6426    err = kIOReturnBadArgument;
6427
6428    return( err );
6429}
6430
6431IOReturn IOHIDSystem::setParamProperties( OSDictionary * dict )
6432{
6433    OSIterator *    iter    = NULL;
6434    IOReturn        ret     = kIOReturnSuccess;
6435    IOReturn        err     = kIOReturnSuccess;
6436
6437    // Tip off devices that these are default parameters
6438    dict->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
6439
6440    ret = cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPre, dict, &iter);
6441
6442    if ( ret == kIOReturnSuccess ) {
6443
6444        // Do the following down calls outside of the gate
6445        if( iter) {
6446            IOService *     eventSrc;
6447            OSDictionary *  validParameters;
6448            while( (eventSrc = (IOService *) iter->getNextObject())) {
6449
6450                if ( OSDynamicCast(IOHIDKeyboard, eventSrc) || OSDynamicCast(IOHIDPointing, eventSrc) || OSDynamicCast(IOHIDConsumer, eventSrc))
6451                    continue;
6452
6453                // Use valid parameters per device.  Basically if the IOHIDevice has a given property
6454                // in its registery we should NOT push it down via setParamProperties as properties
6455                // generated via the global IOHIDSystem::setParamProperties are defaults.
6456                validParameters = createFilteredParamPropertiesForService(eventSrc, dict);
6457                if ( validParameters ) {
6458
6459                    if ( OSDynamicCast(IOHIDevice, eventSrc) )
6460                        ret = ((IOHIDevice *)eventSrc)->setParamProperties( validParameters );
6461                    else if ( OSDynamicCast( IOHIDEventService, eventSrc ) )
6462                        ret = ((IOHIDEventService *)eventSrc)->setSystemProperties( validParameters );
6463
6464                    if( (ret != kIOReturnSuccess) && (ret != kIOReturnBadArgument))
6465                        err = ret;
6466
6467                    dict->merge(validParameters);
6468
6469                    validParameters->release();
6470                }
6471            }
6472            iter->release();
6473        }
6474
6475        // Grab the gate again.
6476        cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPost, dict);
6477    }
6478
6479    return err;
6480}
6481
6482OSDictionary * IOHIDSystem::createFilteredParamPropertiesForService(IOService * service, OSDictionary * dict)
6483{
6484    OSDictionary * validParameters = OSDictionary::withCapacity(4);
6485
6486    if ( !validParameters )
6487        return NULL;
6488
6489    OSDictionary * deviceParameters = NULL;
6490
6491    if ( OSDynamicCast(IOHIDevice, service) ) {
6492        deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDParametersKey);
6493    }
6494    else if ( OSDynamicCast( IOHIDEventService, service ) ) {
6495        deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDEventServicePropertiesKey);
6496    }
6497    if (!OSDynamicCast(OSDictionary, deviceParameters))
6498        OSSafeReleaseNULL(deviceParameters);
6499
6500    OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dict);
6501    if ( iterator ) {
6502        bool done = false;
6503        while (!done) {
6504            OSSymbol * key = NULL;
6505            while ((key = (OSSymbol*)iterator->getNextObject()) != NULL) {
6506                if ( !deviceParameters || !deviceParameters->getObject(key) ) {
6507                    validParameters->setObject(key, dict->getObject(key));
6508                }
6509            }
6510            if (iterator->isValid()) {
6511                done = true;
6512            }
6513            else {
6514                iterator->reset();
6515                validParameters->flushCollection();
6516            }
6517        }
6518        iterator->release();
6519    }
6520
6521    if ( validParameters->getCount() == 0 ) {
6522        validParameters->release();
6523        validParameters = NULL;
6524    }
6525    else {
6526        validParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
6527    }
6528
6529    return validParameters;
6530}
6531
6532
6533IOReturn IOHIDSystem::doSetParamPropertiesPre(IOHIDSystem *self, void * arg0, void * arg1)
6534                        /* IOCommandGate::Action */
6535{
6536    return self->setParamPropertiesPreGated((OSDictionary *)arg0, (OSIterator**)arg1);
6537}
6538
6539IOReturn IOHIDSystem::setParamPropertiesPreGated( OSDictionary * dict, OSIterator ** pOpenIter)
6540{
6541    OSArray *   array;
6542    OSNumber *  number;
6543
6544    // check for null
6545    if (dict == NULL)
6546        return kIOReturnError;
6547
6548    // adding a pending flag here because we will be momentarily openning the gate
6549    // to make down calls into the client, before closing back up again to merge
6550    // the properties.
6551    while ( setParamPropertiesInProgress )
6552        cmdGate->commandSleep(&setParamPropertiesInProgress);
6553
6554    setParamPropertiesInProgress = true;
6555
6556    if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDUseKeyswitchKey))))
6557    {
6558        gUseKeyswitch = number->unsigned32BitValue();
6559    }
6560
6561    if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDClickTimeKey))))
6562    {
6563        UInt64  nano = number->unsigned64BitValue();
6564        nanoseconds_to_absolutetime(nano, &clickTimeThresh);
6565    }
6566
6567    // check the reset before setting the other parameters
6568    if (dict->getObject(kIOHIDScrollCountResetKey)) {
6569        _setScrollCountParameters();
6570    }
6571
6572    _setScrollCountParameters(dict);
6573
6574    if( (array = OSDynamicCast( OSArray,
6575        dict->getObject(kIOHIDClickSpaceKey)))) {
6576
6577        if ((number = OSDynamicCast( OSNumber,
6578        array->getObject(EVSIOSCS_X))))
6579        {
6580            clickSpaceThresh.x = number->unsigned32BitValue();
6581        }
6582        if ((number = OSDynamicCast( OSNumber,
6583        array->getObject(EVSIOSCS_Y))))
6584        {
6585            clickSpaceThresh.y = number->unsigned32BitValue();
6586        }
6587    }
6588
6589    if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDWaitCursorFrameIntervalKey)))) {
6590        uint32_t value = number->unsigned32BitValue();
6591        _cursorWaitDelta = value;
6592        if (_cursorWaitDelta < kTickScale) {
6593            _cursorWaitDelta = kTickScale;
6594        }
6595        scheduleNextPeriodicEvent();
6596    }
6597
6598    if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysOnKey)))) {
6599        if (number->unsigned32BitValue())
6600            stickyKeysState |= (1 << 0);
6601        else
6602            stickyKeysState &= ~(1 << 0);
6603
6604    }
6605
6606    if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysShiftTogglesKey)))) {
6607        if (number->unsigned32BitValue())
6608            stickyKeysState |= (1 << 1);
6609        else
6610            stickyKeysState &= ~(1 << 1);
6611
6612    }
6613
6614    // save all params for new devices
6615    if ( dict->getObject(kIOHIDResetKeyboardKey) ) {
6616        UInt64 nano = EV_DEFAULTKEYREPEAT;
6617        makeNumberParamProperty( dict, kIOHIDKeyRepeatKey, nano, 64 );
6618
6619        nano = EV_DEFAULTINITIALREPEAT;
6620        makeNumberParamProperty( dict, kIOHIDInitialKeyRepeatKey, nano, 64 );
6621    }
6622
6623    if ( dict->getObject(kIOHIDResetPointerKey) ) {
6624        IOFixed fixed = EV_DEFAULTPOINTERACCELLEVEL;
6625        makeNumberParamProperty( dict, kIOHIDPointerAccelerationKey, fixed, sizeof(fixed) << 3);
6626
6627        fixed = kIOHIDButtonMode_EnableRightClick;
6628        makeNumberParamProperty( dict, kIOHIDPointerButtonMode, fixed, sizeof(fixed) << 3);
6629
6630        UInt64 nano = EV_DCLICKTIME;
6631        makeNumberParamProperty( dict, kIOHIDClickTimeKey, nano, 64 );
6632    }
6633
6634    if ( dict->getObject(kIOHIDScrollResetKey) ) {
6635        IOFixed fixed = EV_DEFAULTSCROLLACCELLEVEL;
6636        makeNumberParamProperty( dict, kIOHIDScrollAccelerationKey, fixed, sizeof(fixed) << 3);
6637    }
6638
6639    // update connected input devices
6640    if ( pOpenIter )
6641        *pOpenIter = getOpenProviderIterator();
6642
6643    return kIOReturnSuccess;
6644}
6645
6646void IOHIDSystem::_setScrollCountParameters(OSDictionary *newSettings)
6647{
6648    if (!newSettings) {
6649        newSettings = (OSDictionary*)copyProperty(kIOHIDScrollCountBootDefaultKey);
6650        if (!OSDynamicCast(OSDictionary, newSettings)) {
6651            newSettings->release();
6652            newSettings = NULL;
6653        }
6654    }
6655    else {
6656        newSettings->retain();
6657    }
6658
6659    if (newSettings) {
6660        OSNumber *number = NULL;
6661        OSBoolean *boolean = NULL;
6662        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToStartKey))))
6663        {
6664            _scMinDeltaSqToStart = number->unsigned64BitValue();
6665            _scMinDeltaSqToStart *= _scMinDeltaSqToStart;
6666            if (_scMinDeltaSqToSustain == kDefaultMinimumDelta)
6667                _scMinDeltaSqToSustain = _scMinDeltaSqToStart;
6668            setProperty(kIOHIDScrollCountMinDeltaToStartKey, number);
6669        }
6670
6671        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToSustainKey))))
6672        {
6673            _scMinDeltaSqToSustain = number->unsigned64BitValue();
6674            _scMinDeltaSqToSustain *= _scMinDeltaSqToSustain;
6675            if (_scMinDeltaSqToStart == kDefaultMinimumDelta)
6676                _scMinDeltaSqToStart = _scMinDeltaSqToSustain;
6677            setProperty(kIOHIDScrollCountMinDeltaToSustainKey, number);
6678        }
6679
6680        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaBetweenKey))))
6681        {
6682            UInt64 valueInMs = number->unsigned64BitValue();
6683            nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaBetween);
6684            if (!_scMaxTimeDeltaToSustain)
6685                _scMaxTimeDeltaToSustain = _scMaxTimeDeltaBetween;
6686            setProperty(kIOHIDScrollCountMaxTimeDeltaBetweenKey, number);
6687        }
6688
6689        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaToSustainKey))))
6690        {
6691            UInt64 valueInMs = number->unsigned64BitValue();
6692            nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaToSustain);
6693            if (!_scMaxTimeDeltaBetween)
6694                _scMaxTimeDeltaBetween = _scMaxTimeDeltaToSustain;
6695            setProperty(kIOHIDScrollCountMaxTimeDeltaToSustainKey, number);
6696        }
6697
6698        if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountIgnoreMomentumScrollsKey))))
6699        {
6700            _scIgnoreMomentum = (boolean == kOSBooleanTrue);
6701            setProperty(kIOHIDScrollCountIgnoreMomentumScrollsKey, boolean);
6702        }
6703
6704        if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountMouseCanResetKey))))
6705        {
6706            _scMouseCanReset = (boolean == kOSBooleanTrue);
6707            setProperty(kIOHIDScrollCountMouseCanResetKey, boolean);
6708        }
6709
6710        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxKey))))
6711        {
6712            _scCountMax = number->unsigned16BitValue();
6713            setProperty(kIOHIDScrollCountMaxKey, number);
6714        }
6715
6716        if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountAccelerationFactorKey))))
6717        {
6718            if (number->unsigned32BitValue() > 0) {
6719                _scAccelerationFactor.fromFixed(number->unsigned32BitValue());
6720                setProperty(kIOHIDScrollCountAccelerationFactorKey, number);
6721            }
6722        }
6723
6724        if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountZeroKey))))
6725        {
6726            if (boolean == kOSBooleanTrue) {
6727                log_scroll_state("Resetting _scCount on kIOHIDScrollCountZeroKey%s\n", "");
6728                _scCount = 0;
6729            }
6730        }
6731
6732        newSettings->release();
6733    }
6734}
6735
6736IOReturn IOHIDSystem::doSetParamPropertiesPost(IOHIDSystem *self, void * arg0)
6737                        /* IOCommandGate::Action */
6738{
6739    return self->setParamPropertiesPostGated((OSDictionary *)arg0);
6740}
6741
6742IOReturn IOHIDSystem::setParamPropertiesPostGated( OSDictionary * dict)
6743{
6744    if ( dict->getObject(kIOHIDTemporaryParametersKey) == NULL ) {
6745        bool resetKeyboard  = dict->getObject(kIOHIDResetKeyboardKey) != NULL;
6746        bool resetPointer   = dict->getObject(kIOHIDResetPointerKey) != NULL;
6747        bool resetScroll    = dict->getObject(kIOHIDScrollResetKey) != NULL;
6748
6749        OSDictionary * newParams = OSDictionary::withDictionary( savedParameters );
6750        if( newParams) {
6751            if ( resetKeyboard ) {
6752                dict->removeObject(kIOHIDResetKeyboardKey);
6753            }
6754            if ( resetPointer ) {
6755                dict->removeObject(kIOHIDResetPointerKey);
6756                newParams->removeObject(kIOHIDTrackpadAccelerationType);
6757                newParams->removeObject(kIOHIDMouseAccelerationType);
6758            }
6759            if ( resetScroll ) {
6760                dict->removeObject(kIOHIDScrollResetKey);
6761                newParams->removeObject(kIOHIDTrackpadScrollAccelerationKey);
6762                newParams->removeObject(kIOHIDMouseScrollAccelerationKey);
6763            }
6764
6765            newParams->merge( dict );
6766            setProperty( kIOHIDParametersKey, newParams );
6767            newParams->release();
6768            savedParameters = newParams;
6769        }
6770
6771        // Send anevent notification that the properties changed.
6772        struct evioLLEvent      event;
6773        AbsoluteTime        ts;
6774        // clear event record
6775        bzero( (void *)&event, sizeof event);
6776
6777        event.data.compound.subType = NX_SUBTYPE_HIDPARAMETER_MODIFIED;
6778        clock_get_uptime(&ts);
6779        postEvent(NX_SYSDEFINED, &_cursorHelper.desktopLocation(), ts, &(event.data));
6780
6781    }
6782
6783    // Wake any pending setParamProperties commands.  They
6784    // still won't do much until we return out.
6785    setParamPropertiesInProgress = false;
6786    cmdGate->commandWakeup(&setParamPropertiesInProgress);
6787
6788    return kIOReturnSuccess;
6789}
6790
6791UInt8 IOHIDSystem::getSubtypeForSender(OSObject * sender)
6792{
6793    UInt8 subtype = NX_SUBTYPE_DEFAULT;
6794    if (touchEventPosters->containsObject(sender)) {
6795        subtype = NX_SUBTYPE_MOUSE_TOUCH;
6796    }
6797    return subtype;
6798}
6799
6800void IOHIDSystem::updateMouseMoveEventForSender(OSObject * sender, NXEventData * evData)
6801{
6802    if (sender && evData) {
6803        evData->mouse.subType = getSubtypeForSender(sender);
6804    }
6805}
6806
6807void IOHIDSystem::updateMouseEventForSender(OSObject * sender, NXEventData * evData)
6808{
6809    if (sender && evData) {
6810        evData->mouseMove.subType = getSubtypeForSender(sender);
6811    }
6812}
6813
6814void IOHIDSystem::updateScrollEventForSender(OSObject * sender, NXEventData * evData)
6815{
6816    if (sender && evData) {
6817        if (NX_SUBTYPE_MOUSE_TOUCH == getSubtypeForSender(sender)) {
6818            evData->scrollWheel.reserved1 |= kScrollTypeTouch;
6819        }
6820    }
6821}
6822
6823bool IOHIDSystem::attach( IOService * provider )
6824{
6825    IORegistryEntry *entry = provider;
6826
6827    if (!super::attach(provider))   return false;
6828    while(entry) {
6829        if (kOSBooleanTrue == entry->getProperty("MTEventSource")) {
6830            touchEventPosters->setObject(provider);
6831            entry = 0;
6832        }
6833        else {
6834            entry = entry->getParentEntry(gIOServicePlane);
6835        }
6836    }
6837
6838    return true;
6839}
6840
6841void IOHIDSystem::detach( IOService * provider )
6842{
6843    touchEventPosters->removeObject(provider);
6844    super::detach(provider);
6845}
6846