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 __attribute__((packed)) 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 __attribute__((packed)) 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 __attribute__((packed)) 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,                               // Usage Page (Generic Desktop)
305        0x09, 0x02,                               // Usage (Mouse)
306        0xA1, 0x01,                               // Collection (Application)
307        0x05, 0x09,                               //   Usage Page (Button)
308        0x19, 0x01,                               //   Usage Minimum........... (1)
309        0x29, 0x08,                               //   Usage Maximum........... (8)
310        0x15, 0x00,                               //   Logical Minimum......... (0)
311        0x25, 0x01,                               //   Logical Maximum......... (1)
312        0x95, 0x08,                               //   Report Count............ (8)
313        0x75, 0x01,                               //   Report Size............. (1)
314        0x81, 0x02,                               //   Input...................(Data, Variable, Absolute)
315        0x95, 0x00,                               //   Report Count............ (0)
316        0x75, 0x01,                               //   Report Size............. (1)
317        0x81, 0x00,                               //   Input...................(Data, Array, Absolute)
318        0x05, 0x01,                               //   Usage Page (Generic Desktop)
319        0x09, 0x01,                               //   Usage (Pointer)
320        0xA1, 0x00,                               //   Collection (Physical)
321        0x09, 0x30,                               //     Usage (X)
322        0x09, 0x31,                               //     Usage (Y)
323        0x16, 0x01, 0x80,                         //     Logical Minimum......... (-32767)
324        0x26, 0xFF, 0x7F,                         //     Logical Maximum......... (32767)
325        0x36, 0x00, 0x00,                         //     Physical Minimum........ (0)
326        0x46, 0x00, 0x00,                         //     Physical Maximum........ (0)
327        0x55, 0x00,                               //     Unit Exponent........... (0)
328        0x65, 0x00,                               //     Unit.................... (0)
329        0x75, 0x10,                               //     Report Size............. (16)
330        0x95, 0x02,                               //     Report Count............ (2)
331        0x81, 0x06,                               //     Input...................(Data, Variable, Relative)
332        0xC0,                                     //   End Collection
333        0x00,                                     //   0x00,
334        0x00,                                     //   0x00,
335        0x00,                                     //   0x00,
336        0x00,                                     //   0x00,
337        0x00,                                     //   0x00,
338        0x00,                                     //   0x00,
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        0x00,                                     //   0x00,
350        0x00,                                     //   0x00,
351        0x00,                                     //   0x00,
352        0x00,                                     //   0x00,
353        0xC0,                                     // End Collection
354    };
355
356    bcopy(genMouseDesc, desc, sizeof(GenericMouseDescriptor));
357
358    GenericMouseDescriptor *mouse = (GenericMouseDescriptor *)desc;
359
360    if ((_numButtons <= 8) &&
361        (_numButtons != mouse->buttonRptCountNum))
362    {
363        mouse->buttonRptCountNum = _numButtons;
364        mouse->buttonUsageMaxNum = _numButtons;
365        mouse->fillCountNum = 8 - _numButtons;
366    }
367
368
369    if (_resolution && _resolution != 400)
370    {
371        convert16to8((unsigned short)-32767, mouse->xyLogMinNum);
372        convert16to8(32767, mouse->xyLogMaxNum);
373
374        UInt16 phys = 3276700 / _resolution;
375        convert16to8(-phys, mouse->xyPhyMinNum);
376        convert16to8(phys, mouse->xyPhyMaxNum);
377
378        mouse->xyUnitNum = 0x13;
379        mouse->xyUnitExpNum = 0x0e;
380    }
381
382    if (_isScrollPresent)
383    {
384        UInt8 scrollDes[] = {
385            0x09, 0x38,                               // Usage 56 (0x38)
386            0x15, 0x81,                               // Logical Minimum......... (-127)
387            0x25, 0x7F,                               // Logical Maximum......... (127)
388            0x35, 0x00,                               // Physical Minimum........ (0)
389            0x45, 0x00,                               // Physical Maximum........ (0)
390            0x55, 0x00,                               // Unit Exponent........... (0)
391            0x65, 0x00,                               // Unit.................... (0)
392            0x75, 0x08,                               // Report Size............. (8)
393            0x95, 0x01,                               // Report Count............ (1)
394            0x81, 0x06,                               // Input...................(Data, Variable, Relative)
395        };
396
397        bcopy(scrollDes, &mouse->scrollDescriptor, sizeof(ScrollDescriptor));
398    }
399
400
401    return kIOReturnSuccess;
402}
403
404IOReturn IOHIDPointingDevice::getReport(IOMemoryDescriptor  *report,
405                                        IOHIDReportType     reportType,
406                                        IOOptionBits        options __unused )
407{
408    if (!report)
409        return kIOReturnError;
410
411    if ( reportType != kIOHIDReportTypeInput)
412        return kIOReturnUnsupported;
413
414    report->writeBytes(0, _report->getBytesNoCopy(), min(report->getLength(), _report->getLength()));
415    return kIOReturnSuccess;
416}
417
418void IOHIDPointingDevice::postMouseEvent(UInt8 buttons, UInt16 x, UInt16 y, UInt8 wheel)
419{
420    GenericMouseReport *report = (GenericMouseReport*)_report->getBytesNoCopy();
421
422    if (!report)
423        return;
424
425    report->buttons = buttons;
426    convert16to8(x, report->x);
427    convert16to8(y, report->y);
428    report->wheel = wheel;
429
430    handleReport(_report);
431}
432
433OSString * IOHIDPointingDevice::newProductString() const
434{
435    OSString * string = 0;
436
437    if ( !(string = super::newProductString()) )
438        string = OSString::withCString("Virtual Mouse");
439
440    return string;
441}
442
443