1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <IOKit/IOLib.h>
26
27#include "IOHIDFamilyPrivate.h"
28#include "IOHIDPointingDevice.h"
29
30typedef struct ScrollDescriptor {
31    //09 38:    Usage (Wheel)
32    UInt8 wheelUsageOp;
33    UInt8 wheelUsageNum;
34    //15 81:    Logical Minimum.... (-127)
35    UInt8 wheelLogMinOp;
36    UInt8 wheelLogMinNum;
37    //25 7F:    Logical Maximum.... (127)
38    UInt8 wheelLogMaxOp;
39    UInt8 wheelLogMaxNum;
40    //35 00:    Physical Minimum.... (0)
41    UInt8 wheelPhyMinOp;
42    UInt8 wheelPhyMinNum;
43    //45 00:    Physical Maximum.... (0)
44    UInt8 wheelPhyMaxOp;
45    UInt8 wheelPhyMaxNum;
46    //55 00:    Unit Exponent.... (0)
47    UInt8 wheelUnitExpOp;
48    UInt8 wheelUnitExpNum;
49    //65 00:    Unit.... (0)
50    UInt8 wheelUnitOp;
51    UInt8 wheelUnitNum;
52    //75 08:    Report Size........ (8)
53    UInt8 wheelRptSizeOp;
54    UInt8 wheelRptSizeNum;
55    //95 01:    Report Count....... (1)
56    UInt8 wheelCountOp;
57    UInt8 wheelCountNum;
58    //81 06:    Input (Data)
59    UInt8 wheelInputOp;
60    UInt8 wheelInputNum;
61}ScrollDescriptor;
62
63typedef struct GenericMouseDescriptor {
64    //05 01: Usage Page (Generic Desktop)
65    UInt8 devUsagePageOp;
66    UInt8 devUsagePageNum;
67    //09 02: Usage (Mouse)
68    UInt8 devUsageOp;
69    UInt8 devUsageNum;
70    //A1 01: Collection (Application)
71    UInt8 appCollectionOp;
72    UInt8 appCollectionNum;
73    //05 09:    Usage Page (Button)
74    UInt8 buttonUsagePageOp;
75    UInt8 buttonUsagePageNum;
76    //19 01:    Usage Minimum...... (1)
77    UInt8 buttonUsageMinOp;
78    UInt8 buttonUsageMinNum;
79    //29 08:    Usage Maximum...... (8)
80    UInt8 buttonUsageMaxOp;
81    UInt8 buttonUsageMaxNum;
82    //15 00:    Logical Minimum.... (0)
83    UInt8 buttonLogMinOp;
84    UInt8 buttonLogMinNum;
85    //25 01:    Logical Maximum.... (1)
86    UInt8 buttonLogMaxOp;
87    UInt8 buttonLogMaxNum;
88    //95 08:    Report Count....... (8)
89    UInt8 buttonRptCountOp;
90    UInt8 buttonRptCountNum;
91    //75 01:    Report Size........ (1)
92    UInt8 buttonRptSizeOp;
93    UInt8 buttonRptSizeNum;
94    //81 02:    Input (Data)
95    UInt8 buttonInputOp;
96    UInt8 buttonInputNum;
97    //95 00:    Report Count....... (0)
98    UInt8 fillCountOp;
99    UInt8 fillCountNum;
100    //75 01:    Report Size........ (1)
101    UInt8 fillSizeOp;
102    UInt8 fillSizeNum;
103    //81 00:    Input (Constant)
104    UInt8 fillInputOp;
105    UInt8 fillInputNum;
106    //05 01:    Usage Page (Generic Desktop)
107    UInt8 pointerUsagePageOp;
108    UInt8 pointerUsagePageNum;
109    //09 01:    Usage (Pointer)
110    UInt8 pointerUsageOp;
111    UInt8 pointerUsageNum;
112    //A1 00:    Collection (Physical)
113    UInt8 pysCollectionOp;
114    UInt8 pysCollectionNum;
115    //09 30:    Usage (X)
116    UInt8 xUsageOp;
117    UInt8 xUsageNum;
118    //09 31:    Usage (Y)
119    UInt8 yUsageOp;
120    UInt8 yUsageNum;
121    //16 0:    Logical Minimum.... (0)
122    UInt8 xyLogMinOp;
123    UInt8 xyLogMinNum[2];//
124    //26 0:    Logical Maximum.... (0)
125    UInt8 xyLogMaxOp;
126    UInt8 xyLogMaxNum[2];//
127    //36 00:    Physical Minimum.... (0)
128    UInt8 xyPhyMinOp;
129    UInt8 xyPhyMinNum[2];//
130    //46 00:    Physical Maximum.... (0)
131    UInt8 xyPhyMaxOp;
132    UInt8 xyPhyMaxNum[2];//
133    //55 00:    Unit Exponent.... (0)
134    UInt8 xyUnitExpOp;
135    UInt8 xyUnitExpNum;
136    //65 00:    Unit.... (0)
137    UInt8 xyUnitOp;
138    UInt8 xyUnitNum;
139    //75 10:    Report Size........ (16)
140    UInt8 xyRptSizeOp;
141    UInt8 xyRptSizeNum;
142    //95 02:    Report Count....... (2)
143    UInt8 xyRptCountOp;
144    UInt8 xyRptCountNum;
145    //81 06:    Input (Data)
146    UInt8 xyInputOp;
147    UInt8 xyInputNum;
148    //C0:       End Collection
149    UInt8 pysCollectionEnd;
150
151    ScrollDescriptor scrollDescriptor;
152
153    UInt8 appCollectionEnd;
154} GenericMouseDescriptor;
155
156
157typedef struct GenericMouseReport{
158    UInt8 buttons;
159    UInt8 x[2];
160    UInt8 y[2];
161    UInt8 wheel;
162} GenericMouseReport;
163
164static inline void convert16to8( const UInt16 src,
165                           UInt8 * dst)
166{
167    dst[0] = 0x00ff & src;
168    dst[1] = (0xff00 & src) >> 8;
169}
170
171static Boolean CheckDeviceUsage(IOHIDDevice * device, UInt32 usagePage, UInt32 usage)
172{
173    OSDictionary * matchingDictionary = OSDictionary::withCapacity(2);
174    Boolean ret = FALSE;
175
176    if ( matchingDictionary )
177    {
178        OSNumber * number;
179
180        number = OSNumber::withNumber(usagePage, 32);
181        if ( number )
182        {
183            matchingDictionary->setObject(kIOHIDDeviceUsagePageKey, number);
184            number->release();
185        }
186
187        number = OSNumber::withNumber(usage, 32);
188        if ( number )
189        {
190            matchingDictionary->setObject(kIOHIDDeviceUsageKey, number);
191            number->release();
192        }
193
194        ret = CompareDeviceUsage(device, matchingDictionary, NULL, 0);
195
196        matchingDictionary->release();
197    }
198
199    return ret;
200}
201
202#define super IOHIDDeviceShim
203
204OSDefineMetaClassAndStructors( IOHIDPointingDevice, IOHIDDeviceShim )
205
206
207IOHIDPointingDevice *
208IOHIDPointingDevice::newPointingDeviceAndStart(IOService *owner, UInt8 numButtons, UInt32 resolution, bool scroll, UInt32 location)
209{
210    IOService * provider = owner;
211
212    while ( NULL != (provider = provider->getProvider()) )
213    {
214        if(OSDynamicCast(IOHIDevice, provider) ||
215            (OSDynamicCast(IOHIDDevice, provider) && CheckDeviceUsage((IOHIDDevice*)provider, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse)) )
216        {
217                return  0;
218        }
219    }
220
221    IOHIDPointingDevice * device = new IOHIDPointingDevice;
222
223    if (device)
224    {
225        if (!device->initWithLocation(location)){
226            device->release();
227            return 0;
228        }
229        device->_numButtons = numButtons;
230        device->_resolution = resolution;
231        device->_isScrollPresent = scroll;
232
233        if ( device->attach(owner) )
234        {
235            if (!device->start(owner))
236            {
237                device->detach(owner);
238                device->release();
239                device = 0;
240            }
241        }
242        else
243        {
244            device->release();
245            device = 0;
246        }
247    }
248
249    return device;
250}
251
252
253bool IOHIDPointingDevice::initWithLocation( UInt32 location )
254{
255    if (!super::initWithLocation(location))
256        return false;
257
258    _report = 0;
259
260    return true;
261}
262
263void IOHIDPointingDevice::free()
264{
265    if (_report) _report->release();
266
267    super::free();
268}
269
270bool IOHIDPointingDevice::handleStart( IOService * provider )
271{
272    if (!super::handleStart(provider))
273        return false;
274
275    _pointing = OSDynamicCast(IOHIPointing, provider);
276
277    _report = IOBufferMemoryDescriptor::withCapacity(
278        sizeof(GenericMouseReport), kIODirectionNone, true);
279
280    bzero(_report->getBytesNoCopy(), sizeof(GenericMouseReport));
281
282    return (_report) ? true : false;
283}
284
285IOReturn IOHIDPointingDevice::newReportDescriptor(
286                        IOMemoryDescriptor ** descriptor ) const
287{
288    void 	*desc;
289
290    if (!descriptor)
291        return kIOReturnBadArgument;
292
293    *descriptor = IOBufferMemoryDescriptor::withCapacity(
294        sizeof(GenericMouseDescriptor),
295        kIODirectionNone,
296        true);
297
298    if (! *descriptor)
299        return kIOReturnNoMemory;
300
301    desc = ((IOBufferMemoryDescriptor *)(*descriptor))->getBytesNoCopy();
302
303    UInt8 genMouseDesc[] = {
304        0x05, 0x01,
305        0x09, 0x02,
306        0xA1, 0x01,
307            // Button
308            0x05, 0x09, 0x19, 0x01,
309            0x29, 0x08, 0x15, 0x00,
310            0x25, 0x01, 0x95, 0x08,
311            0x75, 0x01, 0x81, 0x02,
312
313            // Constant
314            0x95, 0x00, 0x75, 0x01,
315            0x81, 0x00,
316
317            // Pointer
318            0x05, 0x01, 0x09, 0x01,
319            0xA1, 0x00,
320                0x09, 0x30,
321                0x09, 0x31,
322
323                // log min/max
324                0x16, 0x01, 0x80,
325                0x26, 0xff, 0x7f,
326
327                // Phy min/max
328                0x36, 0x00, 0x00,
329                0x46, 0x00, 0x00,
330
331                // Unit, Unit Exponent
332                0x55, 0x00,
333                0x65, 0x00,
334
335                0x75, 0x10, 0x95, 0x02,
336                0x81, 0x06,
337            0xC0,
338            // Wheel Padding
339            0x00, 0x00,
340            0x00, 0x00,
341            0x00, 0x00,
342            0x00, 0x00,
343            0x00, 0x00,
344            0x00, 0x00,
345            0x00, 0x00,
346            0x00, 0x00,
347            0x00, 0x00,
348            0x00, 0x00,
349
350        0xC0
351    };
352
353    bcopy(genMouseDesc, desc, sizeof(GenericMouseDescriptor));
354
355    GenericMouseDescriptor *mouse = (GenericMouseDescriptor *)desc;
356
357    if ((_numButtons <= 8) &&
358        (_numButtons != mouse->buttonRptCountNum))
359    {
360        mouse->buttonRptCountNum = _numButtons;
361        mouse->buttonUsageMaxNum = _numButtons;
362        mouse->fillCountNum = 8 - _numButtons;
363    }
364
365
366    if (_resolution && _resolution != 400)
367    {
368        convert16to8((unsigned short)-32767, mouse->xyLogMinNum);
369        convert16to8(32767, mouse->xyLogMaxNum);
370
371        UInt16 phys = 3276700 / _resolution;
372        convert16to8(-phys, mouse->xyPhyMinNum);
373        convert16to8(phys, mouse->xyPhyMaxNum);
374
375        mouse->xyUnitNum = 0x13;
376        mouse->xyUnitExpNum = 0x0e;
377    }
378
379    if (_isScrollPresent)
380    {
381        UInt8 scrollDes[] = {
382            0x09, 0x38,
383            0x15, 0x81,
384            0x25, 0x7f,
385            0x35, 0x00,
386            0x45, 0x00,
387            0x55, 0x00,
388            0x65, 0x00,
389            0x75, 0x08,
390            0x95, 0x01,
391            0x81, 0x06
392        };
393
394        bcopy(scrollDes, &mouse->scrollDescriptor, sizeof(ScrollDescriptor));
395    }
396
397
398    return kIOReturnSuccess;
399}
400
401IOReturn IOHIDPointingDevice::getReport(IOMemoryDescriptor  *report,
402                                        IOHIDReportType     reportType,
403                                        IOOptionBits        options __unused )
404{
405    if (!report)
406        return kIOReturnError;
407
408    if ( reportType != kIOHIDReportTypeInput)
409        return kIOReturnUnsupported;
410
411    report->writeBytes(0, _report->getBytesNoCopy(), min(report->getLength(), _report->getLength()));
412    return kIOReturnSuccess;
413}
414
415void IOHIDPointingDevice::postMouseEvent(UInt8 buttons, UInt16 x, UInt16 y, UInt8 wheel)
416{
417    GenericMouseReport *report = (GenericMouseReport*)_report->getBytesNoCopy();
418
419    if (!report)
420        return;
421
422    report->buttons = buttons;
423    convert16to8(x, report->x);
424    convert16to8(y, report->y);
425    report->wheel = wheel;
426
427    handleReport(_report);
428}
429
430OSString * IOHIDPointingDevice::newProductString() const
431{
432    OSString * string = 0;
433
434    if ( !(string = super::newProductString()) )
435        string = OSString::withCString("Virtual Mouse");
436
437    return string;
438}
439
440