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