1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2009 Apple Computer, Inc.  All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * 07 Jan 2002 		ryepez
25 *			This class is based off IOHIPointing and handles
26 *			USB HID report based pointing devices
27 */
28
29#include <IOKit/IOLib.h>
30#include <IOKit/assert.h>
31#include <IOKit/hidsystem/IOHIDShared.h>
32#include <IOKit/hidsystem/IOHIDDescriptorParser.h>
33
34#include "IOHIDParameter.h"
35#include "IOHIDPointing.h"
36#include "IOHIDKeys.h"
37#include "IOHIDElement.h"
38
39#define super IOHITablet
40OSDefineMetaClassAndStructors(IOHIDPointing, IOHITablet);
41
42//====================================================================================================
43// IOHIDPointing::Pointing
44//====================================================================================================
45IOHIDPointing * IOHIDPointing::Pointing(
46                                UInt32          buttonCount,
47                                IOFixed         pointerResolution,
48                                IOFixed         scrollResolution,
49                                bool            isDispatcher)
50{
51    IOHIDPointing 	*nub 			= new IOHIDPointing;
52
53    if ((nub == 0) || !nub->initWithMouseProperties(buttonCount, pointerResolution, scrollResolution, isDispatcher) )
54    {
55        if (nub) nub->release();
56        return 0;
57    }
58
59    return nub;
60}
61
62
63//====================================================================================================
64// IOHIDPointing::initWithMouseProperties
65//====================================================================================================
66bool IOHIDPointing::initWithMouseProperties(
67                                UInt32          buttonCnt,
68                                IOFixed         pointerResolution,
69                                IOFixed         scrollResolution,
70                                bool            isDispatcher)
71{
72    if (!super::init(0))  return false;
73
74    _numButtons         = (buttonCnt > 0) ? buttonCnt : 1;
75    _resolution         = pointerResolution;
76    _scrollResolution   = scrollResolution;
77    _isDispatcher       = isDispatcher;
78
79    return true;
80}
81
82//====================================================================================================
83// IOHIDPointing::start
84//====================================================================================================
85bool IOHIDPointing::start(IOService *provider)
86{
87
88	_provider = OSDynamicCast(IOHIDEventService, provider);
89
90	if (!_provider)
91		return false;
92
93    // push up properties from our provider
94    setupProperties();
95
96    return super::start(provider);
97}
98
99void IOHIDPointing::stop(IOService *provider)
100{
101    _provider = NULL;
102    super::stop(provider);
103}
104
105//====================================================================================================
106// IOHIDPointing::dispatchAbsolutePointerEvent
107//====================================================================================================
108void IOHIDPointing::dispatchAbsolutePointerEvent(
109                                AbsoluteTime                timeStamp,
110                                IOGPoint *                  newLoc,
111                                IOGBounds *                 bounds,
112                                UInt32                      buttonState,
113                                bool                        inRange,
114                                SInt32                      tipPressure,
115                                SInt32                      tipPressureMin,
116                                SInt32                      tipPressureMax,
117                                IOOptionBits                options)
118{
119    bool    convertToRelative   = ((options & kHIDDispatchOptionPointerAbsolutToRelative) != 0);
120    bool    accelerate          = ((options & kHIDDispatchOptionPointerNoAcceleration) == 0);
121    UInt32  pointingMode        = getPointingMode();
122
123    if ( (((pointingMode & kAccelMouse) != 0) != accelerate) && (((pointingMode & kAbsoluteConvertMouse) != 0) != convertToRelative))
124    {
125        if ( accelerate )
126            pointingMode |= kAccelMouse;
127        else
128            pointingMode &= ~kAccelMouse;
129
130        if ( convertToRelative )
131            pointingMode |= kAbsoluteConvertMouse;
132        else
133            pointingMode &= ~kAbsoluteConvertMouse;
134
135        setPointingMode(pointingMode);
136    }
137
138	super::dispatchAbsolutePointerEvent(newLoc, bounds, buttonState, inRange, tipPressure, tipPressureMin, tipPressureMax, 90, timeStamp);
139}
140
141//====================================================================================================
142// IOHIDPointing::dispatchRelativePointerEvent
143//====================================================================================================
144void IOHIDPointing::dispatchRelativePointerEvent(
145                                AbsoluteTime                timeStamp,
146                                SInt32                      dx,
147                                SInt32                      dy,
148                                UInt32                      buttonState,
149                                IOOptionBits                options)
150{
151    bool    accelerate      = ((options & kHIDDispatchOptionPointerNoAcceleration) == 0);
152    UInt32  pointingMode    = getPointingMode();
153
154    if ( ((pointingMode & kAccelMouse) != 0) != accelerate)
155    {
156        if ( accelerate )
157            pointingMode |= kAccelMouse;
158        else
159            pointingMode &= ~kAccelMouse;
160
161        setPointingMode(pointingMode);
162    }
163
164	super::dispatchRelativePointerEvent(dx, dy, buttonState, timeStamp);
165}
166
167//====================================================================================================
168// IOHIDPointing::dispatchScrollWheelEvent
169//====================================================================================================
170void IOHIDPointing::dispatchScrollWheelEvent(
171                                AbsoluteTime                timeStamp,
172                                SInt32                      deltaAxis1,
173                                SInt32                      deltaAxis2,
174                                UInt32                      deltaAxis3,
175                                IOOptionBits                options)
176{
177    // no good initial check
178    {
179        UInt32  oldEventType    = getScrollType();
180        UInt32  newEventType    = oldEventType & ~( kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny );
181        bool    setScroll       = false;
182
183        UInt32 dispatchKey = kHIDDispatchOptionScrollMomentumContinue;
184        UInt32 eventKey    = kScrollTypeMomentumContinue;
185        bool   dispatchVal = options & dispatchKey ? true : false;
186        bool   eventVal    = oldEventType & eventKey ? true : false;
187        if (dispatchVal != eventVal) {
188            if (dispatchVal) {
189                newEventType |= eventKey;
190            }
191            setScroll = true;
192        }
193
194        dispatchKey = kHIDDispatchOptionScrollMomentumStart;
195        eventKey    = kScrollTypeMomentumStart;
196        dispatchVal = options & dispatchKey ? true : false;
197        eventVal    = oldEventType & eventKey ? true : false;
198        if (dispatchVal != eventVal) {
199            if (dispatchVal) {
200                newEventType |= eventKey;
201            }
202            setScroll = true;
203        }
204
205        dispatchKey = kHIDDispatchOptionScrollMomentumEnd;
206        eventKey    = kScrollTypeMomentumEnd;
207        dispatchVal = options & dispatchKey ? true : false;
208        eventVal    = oldEventType & eventKey ? true : false;
209        if (dispatchVal != eventVal) {
210            if (dispatchVal) {
211                newEventType |= eventKey;
212            }
213            setScroll = true;
214        }
215
216        // Slight idiom change here because kHIDDispatchOptionPhaseAny << 4 == kScrollTypeOptionPhaseAny
217        dispatchKey = (options & kHIDDispatchOptionPhaseAny) << 4;
218        eventKey    = (oldEventType & kScrollTypeOptionPhaseAny);
219        if (dispatchKey != eventKey) {
220            newEventType |= dispatchKey;
221            setScroll = true;
222        }
223
224        if (setScroll) {
225            setScrollType(newEventType);
226        }
227    }
228
229    // rdar://13002702
230    bool    accelerate      = ((options & kHIDDispatchOptionScrollNoAcceleration) == 0) && ((options & kHIDDispatchOptionPhaseEnded) == 0);
231    UInt32  pointingMode    = getPointingMode();
232
233    if (((pointingMode & kAccelScroll) != 0) != accelerate)
234    {
235        if ( accelerate )
236            pointingMode |= kAccelScroll;
237        else
238            pointingMode &= ~kAccelScroll;
239
240        setPointingMode(pointingMode);
241    }
242
243	super::dispatchScrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, timeStamp);
244}
245
246//====================================================================================================
247// IOHIDPointing::generateDeviceID
248//====================================================================================================
249UInt16 IOHIDPointing::generateDeviceID()
250{
251    static UInt16 sNextDeviceID = 0x8000;
252    return sNextDeviceID++;
253}
254
255//====================================================================================================
256// IOHIDPointing::dispatchTabletPointEvent
257//====================================================================================================
258void IOHIDPointing::dispatchTabletEvent(
259                                    NXEventData *           tabletEvent,
260                                    AbsoluteTime            ts)
261{
262    super::dispatchTabletEvent(tabletEvent, ts);
263}
264
265//====================================================================================================
266// IOHIDPointing::dispatchTabletProximityEvent
267//====================================================================================================
268void IOHIDPointing::dispatchProximityEvent(
269                                    NXEventData *           proximityEvent,
270                                    AbsoluteTime            ts)
271{
272    super::dispatchProximityEvent(proximityEvent, ts);
273}
274
275
276// subclasses override
277
278//====================================================================================================
279// IOHIDPointing::buttonCount
280//====================================================================================================
281IOItemCount IOHIDPointing::buttonCount()
282{
283    return _numButtons;
284}
285
286//====================================================================================================
287// IOHIDPointing::resolution
288//====================================================================================================
289IOFixed IOHIDPointing::resolution()
290{
291    return _resolution;
292}
293
294
295//====================================================================================================
296// IOHIDPointing::setupProperties
297//====================================================================================================
298void IOHIDPointing::setupProperties()
299{
300    OSNumber *  number  = NULL;
301
302	// Store the resolution
303	number = _provider ? (OSNumber*)_provider->copyProperty(kIOHIDPointerResolutionKey) : NULL;
304    if ( OSDynamicCast(OSNumber, number) )
305    {
306        IOFixed newResolution = number->unsigned32BitValue();
307        if ( newResolution != 0 ) {
308            _resolution = number->unsigned32BitValue();
309            setProperty(kIOHIDPointerResolutionKey, number);
310            _isDispatcher = FALSE;
311        }
312    }
313    else if ( _resolution )
314    {
315        setProperty(kIOHIDPointerResolutionKey, _resolution, 32);
316    }
317    OSSafeReleaseNULL(number);
318
319	// Store the scroll resolution
320	number = _provider ? (OSNumber*)_provider->copyProperty(kIOHIDScrollResolutionKey) : NULL;
321    if ( OSDynamicCast(OSNumber, number) )
322    {
323        _scrollResolution = number->unsigned32BitValue();
324        setProperty(kIOHIDScrollResolutionKey, number);
325		_isDispatcher = FALSE;
326    }
327    else if ( _scrollResolution )
328    {
329        setProperty(kIOHIDScrollResolutionKey, _scrollResolution, 32);
330    }
331    OSSafeReleaseNULL(number);
332
333	// deal with buttons
334	if ( (_numButtons == 1) &&
335        (NULL != (number = _provider ? (OSNumber*)_provider->copyProperty(kIOHIDPointerButtonCountKey) : NULL)) &&
336	     OSDynamicCast(OSNumber, number) )
337	{
338		_numButtons = number->unsigned32BitValue();
339		_isDispatcher = FALSE;
340	}
341    OSSafeReleaseNULL(number);
342
343    if ( _isDispatcher )
344        setProperty(kIOHIDVirtualHIDevice, kOSBooleanTrue);
345
346    // vtn3: These unsafe, but unlikely to cause a problem. Additionally, making it "safe" is going to be cumbersome and irritating.
347    if (_provider) {
348    setProperty(kIOHIDScrollAccelerationTypeKey, _provider->getProperty( kIOHIDScrollAccelerationTypeKey ));
349    setProperty(kIOHIDPointerAccelerationTypeKey, _provider->getProperty( kIOHIDPointerAccelerationTypeKey ));
350
351    setProperty(kIOHIDPointerAccelerationTableKey, _provider->getProperty( kIOHIDPointerAccelerationTableKey ));
352    setProperty(kIOHIDScrollAccelerationTableKey, _provider->getProperty( kIOHIDScrollAccelerationTableKey ));
353    setProperty(kIOHIDScrollAccelerationTableXKey, _provider->getProperty( kIOHIDScrollAccelerationTableXKey ));
354    setProperty(kIOHIDScrollAccelerationTableYKey, _provider->getProperty( kIOHIDScrollAccelerationTableYKey ));
355    setProperty(kIOHIDScrollAccelerationTableZKey, _provider->getProperty( kIOHIDScrollAccelerationTableZKey ));
356
357    setProperty(kIOHIDScrollReportRateKey, _provider->getProperty( kIOHIDScrollReportRateKey ));
358
359    setProperty( kIOHIDScrollMouseButtonKey, _provider->getProperty( kIOHIDScrollMouseButtonKey ));
360
361    setProperty(kIOHIDScrollResolutionXKey, _provider->getProperty( kIOHIDScrollResolutionXKey ));
362    setProperty(kIOHIDScrollResolutionYKey, _provider->getProperty( kIOHIDScrollResolutionYKey ));
363    setProperty(kIOHIDScrollResolutionZKey, _provider->getProperty( kIOHIDScrollResolutionZKey ));
364    }
365}
366