1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2012 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#define CFRUNLOOP_NEW_API 1
25
26#include <CoreFoundation/CFMachPort.h>
27#include <CoreFoundation/CFPriv.h>
28//#include <IOKit/hid/IOHIDLib.h>
29//#include <unistd.h>
30#include "IOHIDDeviceClass.h"
31#include "IOHIDQueueClass.h"
32#include "IOHIDTransactionClass.h"
33#include "IOHIDPrivateKeys.h"
34#include "IOHIDParserPriv.h"
35
36__BEGIN_DECLS
37#include <asl.h>
38#include <mach/mach.h>
39#include <mach/mach_interface.h>
40#include <IOKit/iokitmig.h>
41#include <IOKit/IOMessage.h>
42#include <IOKit/IODataQueueClient.h>
43#include <System/libkern/OSCrossEndian.h>
44__END_DECLS
45
46#define connectCheck() do {	    \
47    if (!fConnection)		    \
48	return kIOReturnNoDevice;   \
49} while (0)
50
51#define openCheck() do {	    \
52    if (!fIsOpen)		    \
53        return kIOReturnNotOpen;    \
54} while (0)
55
56#define terminatedCheck() do {      \
57    if (fIsTerminated)		    \
58        return kIOReturnNotAttached;\
59} while (0)
60
61#define seizeCheck() do {           \
62    if (!isValid()) \
63        return kIOReturnExclusiveAccess; \
64} while (0)
65
66#define allChecks() do {	    \
67    connectCheck();		    \
68    openCheck();		    \
69    seizeCheck();                   \
70    terminatedCheck();              \
71} while (0)
72
73#ifndef max
74#define max(a, b) \
75    ((a > b) ? a:b)
76#endif
77
78#ifndef min
79#define min(a, b) \
80    ((a < b) ? a:b)
81#endif
82
83typedef struct _IOHIDObsoleteCallbackArgs {
84    IOHIDObsoleteDeviceClass * self;
85    void * callback;
86    void * target;
87    void * refcon;
88    uint32_t * pLength;
89}IOHIDObsoleteCallbackArgs;
90
91enum {
92    kCreateMatchingHIDElementsWithDictionaries = 0x1000
93};
94
95static void ElementCacheApplierFunction(const void *key __unused, const void *value, void *context)
96{
97    _IOHIDElementSetDeviceInterface((IOHIDElementRef)value, (IOHIDDeviceDeviceInterface**)context);
98}
99
100IOCFPlugInInterface ** IOHIDDeviceClass::alloc()
101{
102    IOHIDDeviceClass *me;
103
104    me = new IOHIDDeviceClass;
105    if (me)
106        return (IOCFPlugInInterface **) &me->iunknown.pseudoVTable;
107    else
108        return 0;
109}
110
111IOHIDDeviceClass::IOHIDDeviceClass()
112: IOHIDIUnknown(&sIOCFPlugInInterfaceV1)
113{
114    fHIDDevice.pseudoVTable = (IUnknownVTbl *)  &sHIDDeviceInterfaceV2;
115    fHIDDevice.obj = this;
116
117    fService 			= MACH_PORT_NULL;
118    fConnection 		= MACH_PORT_NULL;
119    fAsyncPort 			= NULL;
120    fNotifyPort 		= NULL;
121    fDeviceValidPort    = MACH_PORT_NULL;
122    fRunLoop 			= NULL;
123    fAsyncCFMachPort    = NULL;
124    fAsyncCFSource      = NULL;
125	fNotifyCFSource		= NULL;
126    fIsOpen 			= false;
127    fIsLUNZero			= false;
128    fIsTerminated		= false;
129    fAsyncPortSetupDone = false;
130	fAsyncPrivateDataRef	= NULL;
131	fNotifyPrivateDataRef   = NULL;
132    fRemovalCallback    = NULL;
133    fRemovalTarget		= NULL;
134    fRemovalRefcon		= NULL;
135    fQueues             = NULL;
136    fElementCache       = NULL;
137    fProperties         = NULL;
138	fCurrentValuesMappedMemory  = 0;
139	fCurrentValuesMappedMemorySize = 0;
140    fElementCount 		= 0;
141    fElementData        = NULL;
142    fElements 			= NULL;
143    fReportHandlerElementCount	= 0;
144    fReportHandlerElementData	= NULL;
145    fReportHandlerElements      = NULL;
146    fReportHandlerQueue = NULL;
147    fInputReportCallback= NULL;
148    fInputReportRefcon  = NULL;
149    fInputReportBuffer  = NULL;
150	fInputReportBufferSize = 0;
151	fInputReportOptions = 0;
152    fGeneration = -1;
153}
154
155IOHIDDeviceClass::~IOHIDDeviceClass()
156{
157    if (fConnection) {
158        IOServiceClose(fConnection);
159        fConnection = MACH_PORT_NULL;
160    }
161
162    if (fService) {
163        IOObjectRelease(fService);
164        fService = MACH_PORT_NULL;
165    }
166
167    if ( fProperties ) {
168        CFRelease(fProperties);
169        fProperties = NULL;
170    }
171
172    if (fReportHandlerQueue){
173        delete fReportHandlerQueue;
174        fReportHandlerQueue = 0;
175    }
176
177    if (fElementCache) {
178        CFDictionaryApplyFunction(fElementCache, ElementCacheApplierFunction, NULL);
179        CFRelease(fElementCache);
180    }
181
182    if (fReportHandlerElementData)
183        CFRelease(fReportHandlerElementData);
184
185    if (fElementData)
186        CFRelease(fElementData);
187
188    if (fQueues)
189        CFRelease(fQueues);
190
191    if ( fDeviceValidPort )
192        mach_port_mod_refs(mach_task_self(), fDeviceValidPort, MACH_PORT_RIGHT_RECEIVE, -1);
193
194	if (fNotifyCFSource) {
195        if ( fRunLoop )
196            CFRunLoopRemoveSource(fRunLoop, fNotifyCFSource, kCFRunLoopDefaultMode);
197        // Per IOKit documentation, this run loop source should not be retained/released
198        fNotifyCFSource = NULL;
199    }
200
201    if (fNotifyPort)
202        IONotificationPortDestroy(fNotifyPort);
203
204    if (fRunLoop)
205        CFRelease(fRunLoop);
206    fRunLoop = NULL;
207
208    // Even though we are leveraging IONotificationPort, we don't actually uses it's event source or CFMachPort
209    // because we wanted to filter the message.  As such, we need to manually clean up our CFMachPort and source.
210    if ( fAsyncCFMachPort ) {
211        CFMachPortInvalidate(fAsyncCFMachPort);
212        CFRelease(fAsyncCFMachPort);
213    }
214
215    if (fAsyncCFSource)
216        CFRelease(fAsyncCFSource);
217
218    if (fAsyncPort)
219        IONotificationPortDestroy(fAsyncPort);
220
221	if (fAsyncPrivateDataRef) {
222		IOObjectRelease(fAsyncPrivateDataRef->notification);
223		free(fAsyncPrivateDataRef);
224	}
225
226	if (fNotifyPrivateDataRef) {
227		IOObjectRelease(fNotifyPrivateDataRef->notification);
228		free(fNotifyPrivateDataRef);
229	}
230}
231
232HRESULT	IOHIDDeviceClass::attachQueue (IOHIDQueueClass * iohidQueue, bool reportHandler)
233{
234    HRESULT res = S_OK;
235
236    iohidQueue->setOwningDevice(this);
237
238    // ���� todo add to list
239    if ( !reportHandler && ( fQueues ||
240        ( fQueues = CFSetCreateMutable(kCFAllocatorDefault, 0, 0) ) ) )
241    {
242        CFSetAddValue(fQueues, (void *)iohidQueue);
243    }
244
245    return res;
246}
247
248HRESULT	IOHIDDeviceClass::detachQueue (IOHIDQueueClass * iohidQueue)
249{
250    HRESULT res = S_OK;
251
252    iohidQueue->setOwningDevice(NULL);
253
254    // ���� todo remove from list
255    if ( fQueues )
256    {
257        CFSetRemoveValue(fQueues, (void *)iohidQueue);
258    }
259
260    return res;
261}
262
263HRESULT IOHIDDeviceClass::attachTransaction (IOHIDTransactionClass * transaction)
264{
265    HRESULT res = S_OK;
266
267    transaction->setOwningDevice(this);
268
269    // ���� todo add to list
270
271    return res;
272
273}
274
275HRESULT IOHIDDeviceClass::detachTransaction (IOHIDTransactionClass * transaction)
276{
277    HRESULT res = S_OK;
278
279    transaction->setOwningDevice(NULL);
280
281    // ���� todo remove from list
282
283    return res;
284}
285
286IOHIDQueueClass * IOHIDDeviceClass::createQueue(bool reportHandler)
287{
288    IOHIDQueueClass * newQueue = new IOHIDQueueClass;
289
290    // attach the queue to us
291    attachQueue (newQueue, reportHandler);
292
293	return newQueue;
294}
295
296HRESULT IOHIDDeviceClass::queryInterfaceQueue (CFUUIDRef uuid __unused, void **ppv)
297{
298    HRESULT res = S_OK;
299
300    // create the queue class
301    IOHIDQueueClass * newQueue = createQueue();
302
303    // add a ref for the one we return
304//    newQueue->addRef();
305
306    // set the return
307    *ppv = newQueue->getInterfaceMap();
308
309    return res;
310}
311
312HRESULT IOHIDDeviceClass::queryInterfaceTransaction (CFUUIDRef uuid __unused, void **ppv)
313{
314    HRESULT res = S_OK;
315
316    IOHIDTransactionClass * transaction = new IOHIDTransactionClass;
317
318    attachTransaction(transaction);
319
320    transaction->create();
321
322    *ppv = transaction->getInterfaceMap();
323
324    return res;
325}
326
327
328HRESULT IOHIDDeviceClass::queryInterface(REFIID iid, void **ppv)
329{
330    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
331    HRESULT res = S_OK;
332
333    if (CFEqual(uuid, kIOHIDDeviceQueueInterfaceID))
334        res = queryInterfaceQueue(uuid, ppv);
335    else if (CFEqual(uuid, kIOHIDDeviceTransactionInterfaceID))
336        res = queryInterfaceTransaction(uuid, ppv);
337    else if (CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID))
338    {
339        *ppv = &iunknown;
340        addRef();
341    }
342    else if (CFEqual(uuid, kIOHIDDeviceDeviceInterfaceID))
343    {
344        *ppv = &fHIDDevice;
345        addRef();
346    }
347    else {
348        *ppv = 0;
349        HIDLog ("not found\n");
350    }
351
352    if (!*ppv)
353        res = E_NOINTERFACE;
354
355    CFRelease(uuid);
356    return res;
357}
358
359IOReturn IOHIDDeviceClass::
360probe(CFDictionaryRef propertyTable __unused, io_service_t inService, SInt32 *order __unused)
361{
362    if (!inService || !IOObjectConformsTo(inService, "IOHIDDevice"))
363        return kIOReturnBadArgument;
364
365    return kIOReturnSuccess;
366}
367
368IOReturn IOHIDDeviceClass::start(CFDictionaryRef propertyTable __unused, io_service_t inService)
369{
370    IOReturn 			res;
371    kern_return_t 		kr;
372    CFMutableDictionaryRef	properties;
373
374    fService = inService;
375    IOObjectRetain(fService);
376
377    res = IOServiceOpen(fService, mach_task_self(), kIOHIDLibUserClientConnectManager, &fConnection);
378    if (res != kIOReturnSuccess)
379        return res;
380
381    connectCheck();
382
383    fNotifyPort = IONotificationPortCreate(kIOMasterPortDefault);
384
385    // Per IOKit documentation, this run loop source should not be retained/released
386    fNotifyCFSource = IONotificationPortGetRunLoopSource(fNotifyPort);
387
388    fRunLoop = CFRunLoopGetMain();
389    CFRetain(fRunLoop);
390    CFRunLoopAddSource(fRunLoop, fNotifyCFSource, kCFRunLoopDefaultMode);
391
392    fNotifyPrivateDataRef = (MyPrivateData *)malloc(sizeof(MyPrivateData));
393    bzero(fNotifyPrivateDataRef, sizeof(MyPrivateData));
394
395    fNotifyPrivateDataRef->self		= this;
396
397    // Register for an interest notification of this device being removed. Use a reference to our
398    // private data as the refCon which will be passed to the notification callback.
399    kr = IOServiceAddInterestNotification( fNotifyPort,
400                                            fService,
401                                            kIOGeneralInterest,
402                                            IOHIDDeviceClass::_deviceNotification,
403                                            fNotifyPrivateDataRef,
404                                            &(fNotifyPrivateDataRef->notification));
405
406
407    // Create port to determine if mem maps are valid.  Use
408    // IODataQueueAllocateNotificationPort cause that limits the msg queue to
409    // one entry.
410    fDeviceValidPort = IODataQueueAllocateNotificationPort();
411    if (fDeviceValidPort == MACH_PORT_NULL)
412        return kIOReturnNoMemory;
413
414    kr = IOConnectSetNotificationPort(fConnection, kIOHIDLibUserClientDeviceValidPortType, fDeviceValidPort, NULL);
415    if (kr != kIOReturnSuccess)
416        return kr;
417
418    uint64_t output[2];
419    uint32_t len = 2;
420
421    kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientGetElementCount, 0, 0, output, &len);
422    if (kr != kIOReturnSuccess)
423        return kr;
424
425    HIDLog("IOHIDDeviceClass::start: elementCount=%lld reportHandlerCount=%lld\n", output[0], output[1]);
426
427    fElementCount               = output[0];
428    fReportHandlerElementCount  = output[1];
429
430
431    buildElements(kHIDElementType, &fElementData, &fElements, &fElementCount);
432    buildElements(kHIDReportHandlerType, &fReportHandlerElementData, &fReportHandlerElements, &fReportHandlerElementCount);
433
434	fElementCache = CFDictionaryCreateMutable(
435                                            kCFAllocatorDefault,
436                                            0,
437                                            &kCFTypeDictionaryKeyCallBacks,
438                                            &kCFTypeDictionaryValueCallBacks);
439
440    if ( !fElementCache )
441        return kIOReturnNoMemory;
442
443    fProperties = CFDictionaryCreateMutable(
444                                            kCFAllocatorDefault,
445                                            0,
446                                            &kCFTypeDictionaryKeyCallBacks,
447                                            &kCFTypeDictionaryValueCallBacks);
448
449    if ( !fProperties )
450        return kIOReturnNoMemory;
451
452    return kIOReturnSuccess;
453}
454
455IOReturn IOHIDDeviceClass::createSharedMemory(uint64_t generation)
456{
457    // get the shared memory
458    if ( generation == fGeneration )
459        return kIOReturnSuccess;
460
461#if !__LP64__
462    vm_address_t        address = nil;
463    vm_size_t           size    = 0;
464#else
465    mach_vm_address_t   address = nil;
466    mach_vm_size_t      size    = 0;
467#endif
468    IOReturn ret = IOConnectMapMemory (
469                                fConnection,
470                                kIOHIDLibUserClientElementValuesType,
471                                mach_task_self(),
472                                &address,
473                                &size,
474                                kIOMapAnywhere	);
475
476    if (ret != kIOReturnSuccess)
477        return kIOReturnError;
478
479    fCurrentValuesMappedMemory = address;
480    fCurrentValuesMappedMemorySize = size;
481
482    if ( !fCurrentValuesMappedMemory )
483        return kIOReturnNoMemory;
484
485    fGeneration = generation;
486
487    return kIOReturnSuccess;
488}
489
490IOReturn IOHIDDeviceClass::releaseSharedMemory()
491{
492    // finished with the shared memory
493    if (!fCurrentValuesMappedMemory)
494        return kIOReturnSuccess;
495
496    IOReturn ret = IOConnectUnmapMemory (
497                                fConnection,
498                                kIOHIDLibUserClientElementValuesType,
499                                mach_task_self(),
500                                fCurrentValuesMappedMemory);
501
502    fCurrentValuesMappedMemory      = 0;
503    fCurrentValuesMappedMemorySize  = 0;
504
505    return ret;
506}
507
508Boolean IOHIDDeviceClass::isValid()
509{
510    IOReturn kr;
511
512    struct {
513            mach_msg_header_t	msgHdr;
514            OSNotificationHeader	notifyHeader;
515            mach_msg_trailer_t	trailer;
516    } msg;
517
518    kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), fDeviceValidPort, 0, MACH_PORT_NULL);
519
520    switch ( kr ) {
521        case MACH_MSG_SUCCESS:
522            uint64_t args[2];
523            uint32_t len = 2;
524
525            args[0] = 1;
526            args[1] = fGeneration;
527
528            kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientDeviceIsValid, 0, 0, args, &len);
529
530            if ( args[0] /*valid*/ )
531                kr = createSharedMemory(args[1] /*generation */);
532            else {
533                fCurrentValuesMappedMemory      = 0;
534                fCurrentValuesMappedMemorySize  = 0;
535            }
536            break;
537    };
538
539    return fCurrentValuesMappedMemory != 0;
540}
541
542
543IOReturn IOHIDDeviceClass::getProperty(CFStringRef key, CFTypeRef * pProperty)
544{
545    CFTypeRef property = CFDictionaryGetValue(fProperties, key);
546
547    if ( !property ) {
548        property = IORegistryEntrySearchCFProperty(fService, kIOServicePlane, key, kCFAllocatorDefault, kIORegistryIterateRecursively| kIORegistryIterateParents);
549        if ( property ) {
550            CFDictionarySetValue(fProperties, key, property);
551            CFRelease(property);
552        }
553    }
554
555    if ( pProperty )
556        *pProperty = property;
557
558    return kIOReturnSuccess;
559}
560
561IOReturn IOHIDDeviceClass::setProperty(CFStringRef key, CFTypeRef property)
562{
563    CFDictionarySetValue(fProperties, key, property);
564
565    return kIOReturnSuccess;
566}
567
568// RY: There are 2 General Interest notification event sources.
569// One is operating on the main run loop via fNotifyPort and is internal
570// to the IOHIDDeviceClass.  The other is used by the client to get removal
571// notification via fAsyncPort.  This method is used by both and disguished
572// by the port in the refcon.
573void IOHIDDeviceClass::_deviceNotification(void *refCon, io_service_t service __unused, natural_t messageType, void * messageArgument )
574{
575    IOHIDDeviceClass *  self;
576    MyPrivateData *     privateDataRef  = (MyPrivateData *) refCon;
577    IOOptionBits        options         = (IOOptionBits)((addr64_t)messageArgument);
578
579    if (!privateDataRef)
580        return;
581
582    self = privateDataRef->self;
583
584    if (!self || (messageType != kIOMessageServiceIsTerminated))
585        return;
586
587    self->fIsTerminated = true;
588
589    if ( privateDataRef != self->fAsyncPrivateDataRef)
590        return;
591
592    if (self->fRemovalCallback)
593    {
594        ((IOHIDCallbackFunction)self->fRemovalCallback)(
595                                        self->fRemovalTarget,
596                                        kIOReturnSuccess,
597                                        self->fRemovalRefcon,
598                                        (void *)&(self->fHIDDevice));
599    }
600    // Free up the notificaiton
601    IOObjectRelease(privateDataRef->notification);
602    free(self->fAsyncPrivateDataRef);
603    self->fAsyncPrivateDataRef = 0;
604}
605
606IOReturn IOHIDDeviceClass::getAsyncEventSource(CFTypeRef *source)
607{
608    connectCheck();
609
610    if (!fAsyncPort) {
611        IOReturn ret;
612        ret = getAsyncPort(0);
613        if (kIOReturnSuccess != ret)
614            return ret;
615    }
616
617    if (!fAsyncCFMachPort) {
618        CFMachPortContext   context;
619        Boolean             shouldFreeInfo = FALSE;
620
621        context.version         = 1;
622        context.info            = this;
623        context.retain          = NULL;
624        context.release         = NULL;
625        context.copyDescription = NULL;
626
627        fAsyncCFMachPort = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(fAsyncPort),
628                    (CFMachPortCallBack) _cfmachPortCallback,
629                    &context, &shouldFreeInfo);
630
631        if ( shouldFreeInfo ) {
632            // The CFMachPort we got might not work, but we'll proceed with it anyway.
633            asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s received an unexpected reused CFMachPort", __func__);
634        }
635
636        if (!fAsyncCFMachPort)
637            return kIOReturnNoMemory;
638    }
639
640    if ( !fAsyncCFSource ) {
641        fAsyncCFSource = CFMachPortCreateRunLoopSource(NULL, fAsyncCFMachPort, 0);
642        if (!fAsyncCFSource)
643            return kIOReturnNoMemory;
644    }
645
646    if (source)
647        *source = fAsyncCFSource;
648
649    return kIOReturnSuccess;
650}
651
652IOReturn IOHIDDeviceClass::getAsyncPort(mach_port_t *port)
653{
654    IOReturn ret = kIOReturnSuccess;
655
656    connectCheck();
657
658    if ( !fAsyncPort )  {
659
660        fAsyncPort = IONotificationPortCreate(kIOMasterPortDefault);
661        if (!fAsyncPort)
662            return kIOReturnNoMemory;
663
664        if (fIsOpen)
665            ret = finishAsyncPortSetup();
666    }
667
668    if (port)
669        *port = IONotificationPortGetMachPort(fAsyncPort);
670
671    return ret;
672}
673
674IOReturn IOHIDDeviceClass::finishAsyncPortSetup()
675{
676	finishReportHandlerQueueSetup();
677
678    fAsyncPortSetupDone = true;
679
680    return IOConnectSetNotificationPort(fConnection, kIOHIDLibUserClientAsyncPortType, IONotificationPortGetMachPort(fAsyncPort), NULL);
681}
682
683IOReturn IOHIDDeviceClass::open(IOOptionBits options)
684{
685    IOReturn ret = kIOReturnSuccess;
686
687    connectCheck();
688
689    do {
690        // ���todo, check flags to see if different (if so, we might need to reopen)
691        if (fIsOpen)
692            break;
693
694        uint32_t len = 0;
695        uint64_t input = options;
696
697        ret = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientOpen, &input, 1, 0, &len);
698
699        if (ret != kIOReturnSuccess)
700            break;
701
702        fIsOpen = true;
703
704        if (!fAsyncPortSetupDone && fAsyncPort) {
705            ret = finishAsyncPortSetup();
706
707            if (ret != kIOReturnSuccess) {
708                close();
709                break;
710            }
711        }
712
713        isValid();
714
715    } while (false);
716
717    return ret;
718}
719
720IOReturn IOHIDDeviceClass::close(IOOptionBits options __unused)
721{
722    IOReturn ret;
723
724    openCheck();
725    connectCheck();
726
727    ret = releaseSharedMemory();
728
729    uint32_t len = 0;
730
731    ret = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientClose, 0, 0, 0, &len);
732
733    fIsOpen = false;
734    fIsLUNZero = false;
735
736    return ret;
737}
738
739IOReturn IOHIDDeviceClass::getElementValue(IOHIDElementRef element, IOHIDValueRef * pEvent, uint32_t timeout __unused, IOHIDValueCallback callback __unused, void * refcon __unused, IOOptionBits options)
740{
741    uint32_t generation = 0;
742    IOReturn kr = getCurrentElementValueAndGeneration(element, pEvent, &generation);
743
744    // If the generation is 0, this element has never
745    // been processed.  We should query the element
746    //  to get the current value.
747    if ((kr == kIOReturnSuccess) && ((options & kHIDGetElementValuePreventPoll) == 0) && ((options & kHIDGetElementValueForcePoll) || ((IOHIDElementGetType(element) == kIOHIDElementTypeFeature) && (generation == 0))))
748    {
749        uint64_t    input = (uint64_t) IOHIDElementGetCookie(element);
750        size_t    outputCount = 0;
751
752        allChecks();
753
754		kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientUpdateElementValues, &input, 1, 0, 0);
755
756		if (kr == kIOReturnSuccess)
757			kr = getCurrentElementValueAndGeneration(element, pEvent);
758	}
759
760    return kr;
761}
762
763IOReturn IOHIDDeviceClass::setElementValue(IOHIDElementRef element, IOHIDValueRef event, uint32_t timeout __unused, IOHIDValueCallback callback __unused, void * refcon __unused, IOOptionBits options)
764{
765    kern_return_t           kr = kIOReturnBadArgument;
766    IOHIDElementStruct		elementStruct;
767
768    allChecks();
769
770    if (!getElementStruct(IOHIDElementGetCookie(element), &elementStruct))
771        return kr;
772
773    // we are only interested feature and output elements
774    if ((elementStruct.type != kIOHIDElementTypeFeature) && (elementStruct.type != kIOHIDElementTypeOutput))
775        return kr;
776
777    // get ptr to shared memory for this element
778    if (elementStruct.valueLocation < fCurrentValuesMappedMemorySize)
779    {
780        IOHIDElementValue * elementValue = (IOHIDElementValue *)(fCurrentValuesMappedMemory + elementStruct.valueLocation);
781
782        _IOHIDValueCopyToElementValuePtr(event, elementValue);
783
784        // See if the value is pended
785        if ( options & kHIDSetElementValuePendEvent )
786            return kIOReturnSuccess;
787
788        uint64_t    input = (uint64_t)IOHIDElementGetCookie(element);
789        uint32_t    outputCount = 0;
790
791        kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientPostElementValues, &input, 1, 0, &outputCount);
792    }
793
794    return kr;
795}
796
797IOReturn IOHIDDeviceClass::getCurrentElementValueAndGeneration(IOHIDElementRef element, IOHIDValueRef *pEvent, uint32_t * pGeneration)
798{
799    IOHIDElementStruct  elementStruct;
800    IOHIDEventStruct    valueEvent;
801    IOHIDValueRef       valueRef;
802
803    allChecks();
804
805    if (!element || !getElementStruct(IOHIDElementGetCookie(element), &elementStruct) || (elementStruct.type == kIOHIDElementTypeCollection))
806        return kIOReturnBadArgument;
807
808    // get the value
809    // get ptr to shared memory for this elementStruct
810    if (elementStruct.valueLocation < fCurrentValuesMappedMemorySize)
811    {
812        IOHIDElementValue * elementValue = (IOHIDElementValue *)(fCurrentValuesMappedMemory + elementStruct.valueLocation);
813        uint64_t            timeStamp    = *((uint64_t *)&(elementValue->timestamp));
814        uint32_t            generation   = elementValue->generation;
815
816        ROSETTA_ONLY(
817            timeStamp   = OSSwapInt64(timeStamp);
818            generation  = OSSwapInt32(generation);
819        );
820
821        valueRef = _IOHIDElementGetValue(element);
822
823        if ( !valueRef || (IOHIDValueGetTimeStamp(valueRef) < timeStamp) )
824        {
825            valueRef = _IOHIDValueCreateWithElementValuePtr(kCFAllocatorDefault, element, elementValue);
826
827            if (valueRef) {
828                _IOHIDElementSetValue(element, valueRef);
829                CFRelease(valueRef); // Should be retained by the element
830            }
831        }
832
833        if (pEvent)
834            *pEvent = valueRef;
835
836        if ( pGeneration )
837            *pGeneration = generation;
838    }
839
840    return kIOReturnSuccess;
841
842}
843
844struct IOHIDReportRefCon {
845    IOHIDReportType type;
846    uint8_t *       buffer;
847    uint32_t        reportID;
848    IOHIDReportCallback	callback;
849    void *			callbackRefcon;
850    void *			sender;
851};
852
853IOReturn IOHIDDeviceClass::setReport(IOHIDReportType        reportType,
854                                     uint32_t               reportID,
855                                     const uint8_t          *report,
856                                     CFIndex                reportLength,
857                                     uint32_t               timeout,
858                                     IOHIDReportCallback    callback,
859                                     void                   *refcon,
860                                     IOOptionBits           options __unused)
861{
862    uint64_t    in[3];
863    IOReturn    ret;
864
865    allChecks();
866
867    // Async setReport
868    if (callback)
869    {
870        if (!fAsyncPort)
871            return kIOReturnError; //kIOUSBNoAsyncPortErr;
872
873        io_async_ref64_t    asyncRef;
874        IOHIDReportRefCon * hidRefcon = 0;
875
876
877        in[0] = reportType;
878        in[1] = reportID;
879        in[2] = timeout;
880
881        hidRefcon = (IOHIDReportRefCon *)malloc(sizeof(IOHIDReportRefCon));
882
883        if (!hidRefcon)
884            return kIOReturnError;
885
886        hidRefcon->type         = reportType;
887        hidRefcon->reportID     = reportID;
888        hidRefcon->buffer       = (uint8_t *)report;
889        hidRefcon->callback		= callback;
890        hidRefcon->callbackRefcon 	= refcon;
891        hidRefcon->sender		= &fHIDDevice;
892
893        asyncRef[kIOAsyncCalloutFuncIndex]      = (uint64_t)_hidReportCallback;
894        asyncRef[kIOAsyncCalloutRefconIndex]    = (uint64_t)hidRefcon;
895
896        ret = IOConnectCallAsyncMethod(fConnection, kIOHIDLibUserClientSetReport, IONotificationPortGetMachPort(fAsyncPort), asyncRef, kIOAsyncCalloutCount, in, 3, report, reportLength, 0, 0, 0, 0);
897
898    }
899    else
900    {
901        in[0] = reportType;
902        in[1] = reportID;
903        in[2] = 0;
904        ret = IOConnectCallMethod(fConnection, kIOHIDLibUserClientSetReport, in, 3, report, (size_t)reportLength, 0, 0, 0, 0);
905    }
906
907    if (ret == MACH_SEND_INVALID_DEST)
908    {
909	fIsOpen = false;
910	fConnection = MACH_PORT_NULL;
911	ret = kIOReturnNoDevice;
912    }
913    return ret;
914
915}
916
917
918IOReturn
919IOHIDDeviceClass::getReport(IOHIDReportType     reportType,
920                            uint32_t            reportID,
921                            uint8_t             *report,
922                            CFIndex             *pReportLength,
923                            uint32_t            timeout,
924                            IOHIDReportCallback callback,
925                            void                *refcon,
926                            IOOptionBits        options __unused)
927{
928    uint64_t    in[3];
929    IOReturn    ret;
930    size_t      reportLength = *pReportLength;
931
932    allChecks();
933
934    if (!pReportLength || (*pReportLength < 0))
935    	return kIOReturnNoMemory;
936
937    // Async getReport
938    if (callback)
939    {
940        if (!fAsyncPort)
941            return kIOReturnError; //kIOUSBNoAsyncPortErr;
942
943        io_async_ref64_t    asyncRef;
944        IOHIDReportRefCon * hidRefcon = 0;
945
946
947        in[0] = reportType;
948        in[1] = reportID;
949        in[2] = timeout;
950
951        hidRefcon = (IOHIDReportRefCon *)malloc(sizeof(IOHIDReportRefCon));
952
953        if (!hidRefcon)
954            return kIOReturnError;
955
956        hidRefcon->type         = reportType;
957        hidRefcon->reportID     = reportID;
958        hidRefcon->buffer       = report;
959        hidRefcon->callback		= callback;
960        hidRefcon->callbackRefcon 	= refcon;
961        hidRefcon->sender		= &fHIDDevice;
962
963        asyncRef[kIOAsyncCalloutFuncIndex]      = (uint64_t)_hidReportCallback;
964        asyncRef[kIOAsyncCalloutRefconIndex]    = (uint64_t)hidRefcon;
965
966
967        ret = IOConnectCallAsyncMethod(fConnection, kIOHIDLibUserClientGetReport, IONotificationPortGetMachPort(fAsyncPort), asyncRef, kIOAsyncCalloutCount, in, 3, 0, 0, 0, 0, report, &reportLength);
968    }
969    else
970    {
971        in[0] = reportType;
972        in[1] = reportID;
973        in[2] = 0;
974        ret = IOConnectCallMethod(fConnection, kIOHIDLibUserClientGetReport, in, 3, 0, 0, 0, 0, report, &reportLength);
975    }
976
977    *pReportLength = reportLength;
978
979    if (ret == MACH_SEND_INVALID_DEST)
980    {
981		fIsOpen = false;
982		fConnection = MACH_PORT_NULL;
983		ret = kIOReturnNoDevice;
984    }
985    return ret;
986}
987
988
989bool IOHIDDeviceClass::getElementDictIntValue(CFDictionaryRef element, CFStringRef key, uint32_t * value)
990{
991    CFTypeRef   object = CFDictionaryGetValue (element, key);
992    uint32_t    number = 0;
993    CFTypeID    typeID = object ? CFGetTypeID(object) : 0; // _kCFRuntimeNotATypeID
994
995    if (!value) {
996        char buff[64] = "unknown";
997        if (key)
998            CFStringGetCString(key, buff, 64, kCFStringEncodingUTF8);
999        asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s called with no value for %s\n", __PRETTY_FUNCTION__, buff);
1000    }
1001    else {
1002        if (typeID == CFNumberGetTypeID())
1003        {
1004            if (CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, &number))
1005            {
1006                *value = number;
1007                return true;
1008            }
1009        }
1010        else if (typeID == CFBooleanGetTypeID())
1011        {
1012            *value = (object == kCFBooleanTrue);
1013            return true;
1014        }
1015    }
1016    return false;
1017}
1018
1019void IOHIDDeviceClass::setElementDictIntValue(CFMutableDictionaryRef element, CFStringRef key, uint32_t value)
1020{
1021    CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
1022
1023    if ( !number )
1024        return;
1025
1026    CFDictionarySetValue(element, key, number);
1027    CFRelease(number);
1028}
1029
1030void IOHIDDeviceClass::setElementDictBoolValue( CFMutableDictionaryRef element, CFStringRef key, bool value)
1031{
1032    CFBooleanRef boolVal = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1033    CFDictionarySetValue(element, key, boolVal);
1034}
1035
1036
1037CFTypeRef IOHIDDeviceClass::createElement(CFDataRef data, IOHIDElementStruct * element, uint32_t index, CFTypeRef parentElement, CFMutableDictionaryRef elementCache, bool * isElementCached, IOOptionBits options)
1038{
1039    CFTypeRef   type = 0;
1040    CFNumberRef key = 0;
1041    uint32_t    cookie = element->cookieMin + index;
1042
1043    if ( elementCache )
1044    {
1045        key = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &cookie);
1046
1047        if ( key )
1048        {
1049            type = CFDictionaryGetValue(elementCache, key);
1050
1051            if ( type )
1052            {
1053                if (isElementCached)
1054                    *isElementCached = true;
1055
1056                CFRetain(type);
1057                CFRelease(key);
1058
1059                return type;
1060            }
1061        }
1062    }
1063
1064    if ( options & kCreateMatchingHIDElementsWithDictionaries )
1065    {
1066        CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1067
1068        if (dictionary)
1069        {
1070            uint32_t reportCount = element->reportCount;
1071            uint32_t size = element->size;
1072
1073            do {
1074                if ( parentElement )
1075                    CFDictionarySetValue(dictionary, CFSTR(kIOHIDElementParentCollectionKey), parentElement);
1076
1077                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCookieKey), cookie);
1078                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCollectionCookieKey), element->parentCookie);
1079                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementTypeKey), element->type);
1080                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUsageKey), element->usageMin + ((element->usageMin!=element->usageMax) ? index : 0));
1081                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUsagePageKey), element->usagePage);
1082                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportIDKey), element->reportID);
1083
1084                if ( element->type == kIOHIDElementTypeCollection )
1085                {
1086                    setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCollectionTypeKey), element->collectionType);
1087                    break;
1088                }
1089
1090                if ( element->duplicateValueSize && (element->duplicateIndex != 0xffffffff))
1091                {
1092                    reportCount = 1;
1093                    size        = element->reportSize;
1094                    setElementDictIntValue(dictionary, CFSTR(kIOHIDElementDuplicateIndexKey), element->duplicateIndex + ((index>0) ? index-1: 0));
1095                }
1096
1097                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementSizeKey), size);
1098                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportSizeKey), element->reportSize);
1099                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportCountKey), reportCount);
1100
1101                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementHasNullStateKey), (element->flags & kHIDDataNullStateBit) == kHIDDataNullState);
1102                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementHasPreferredStateKey), (element->flags & kHIDDataNoPreferredBit) != kHIDDataNoPreferred);
1103                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsNonLinearKey), (element->flags & kHIDDataNonlinearBit) == kHIDDataNonlinear);
1104                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsRelativeKey), (element->flags & kHIDDataRelativeBit) == kHIDDataRelative);
1105                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsWrappingKey), (element->flags & kHIDDataWrapBit) == kHIDDataWrap);
1106                setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsArrayKey), (element->flags & kHIDDataArrayBit) == kHIDDataArray);
1107
1108                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementMaxKey), element->max);
1109                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementMinKey), element->min);
1110                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementScaledMaxKey), element->scaledMax);
1111                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementScaledMinKey), element->scaledMin);
1112                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUnitKey), element->unit);
1113                setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUnitExponentKey), element->unitExponent);
1114
1115            } while (false);
1116
1117            type = dictionary;
1118        }
1119    }
1120    else
1121    {
1122        type = _IOHIDElementCreateWithParentAndData(kCFAllocatorDefault, (IOHIDElementRef)parentElement, data, element, index);
1123
1124        if (type)
1125            _IOHIDElementSetDeviceInterface((IOHIDElementRef)type, (IOHIDDeviceDeviceInterface **)&fHIDDevice);
1126    }
1127
1128    if ( key && type && elementCache )
1129        CFDictionarySetValue(elementCache, key, type);
1130
1131    if (key)
1132        CFRelease(key);
1133
1134    if (isElementCached)
1135        *isElementCached = false;
1136
1137	return type;
1138}
1139
1140IOReturn
1141IOHIDDeviceClass::copyMatchingElements(CFDictionaryRef matchingDict, CFArrayRef * elements, CFTypeRef parentElement, CFMutableDictionaryRef elementCache, IOOptionBits options)
1142{
1143   if (!elements)
1144        return kIOReturnBadArgument;
1145
1146    IOHIDElementStruct      element;
1147    CFMutableArrayRef       tempElements        = 0;
1148    CFMutableArrayRef       subElements         = 0;
1149    CFTypeRef               elementType         = 0;
1150    CFTypeRef               object              = 0;
1151    uint32_t                number              = 0;
1152    uint32_t                index               = 0;
1153    uint32_t                matchingCookieMin   = 0;
1154    uint32_t                matchingCookieMax   = 0;
1155    uint32_t                matchingUsageMin    = 0;
1156    uint32_t                matchingUsageMax    = 0;
1157    uint32_t                matchingDupIndex    = 0;
1158    bool                    isMatchingCookieMin = false;
1159    bool                    isMatchingCookieMax = false;
1160    bool                    isMatchingUsageMin  = false;
1161    bool                    isMatchingUsageMax  = false;
1162    bool                    isMatchingDupIndex  = false;
1163    bool                    isElementCached     = false;
1164    bool                    isDuplicateRoot     = false;
1165
1166
1167    if (!(tempElements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)))
1168    {
1169        *elements = 0;
1170        return kIOReturnNoMemory;
1171    }
1172
1173    for (index=0; index<fElementCount; index++)
1174    {
1175        isMatchingCookieMin = isMatchingCookieMax = false;
1176        isMatchingUsageMax = isMatchingUsageMin = false;
1177        matchingCookieMin = matchingCookieMax = 0;
1178        matchingUsageMin = matchingUsageMax = 0;
1179        isDuplicateRoot = (fElements[index].duplicateValueSize != 0);
1180
1181        if ( matchingDict )
1182        {
1183            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieKey), &number) )
1184            {
1185                if ((number < fElements[index].cookieMin) || (number > fElements[index].cookieMax))
1186                    continue;
1187
1188                matchingCookieMin = number;
1189                matchingCookieMax = number;
1190                isMatchingCookieMin = true;
1191                isMatchingCookieMax = true;
1192            }
1193            else
1194            {
1195                if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieMinKey), &number) )
1196                {
1197                    if ( number < fElements[index].cookieMin )
1198                        continue;
1199
1200                    matchingCookieMin = number;
1201                    isMatchingCookieMin = true;
1202                }
1203
1204                if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieMaxKey), &number) )
1205                {
1206                    if ( number > fElements[index].cookieMax )
1207                        continue;
1208
1209                    matchingCookieMax = number;
1210                    isMatchingCookieMax = true;
1211                }
1212            }
1213
1214            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCollectionCookieKey), &number) &&
1215                (number != fElements[index].parentCookie))
1216                continue;
1217
1218            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementTypeKey), &number) &&
1219                (number != fElements[index].type))
1220                continue;
1221
1222            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCollectionTypeKey), &number) &&
1223                (number != fElements[index].collectionType))
1224                continue;
1225
1226            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportIDKey), &number) &&
1227                (number != fElements[index].reportID))
1228                continue;
1229
1230            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageKey), &number) )
1231            {
1232                if ((number < fElements[index].usageMin) || (number > fElements[index].usageMax))
1233                    continue;
1234
1235                matchingUsageMin    = number;
1236                matchingUsageMax    = number;
1237                isMatchingUsageMin  = true;
1238                isMatchingUsageMax  = true;
1239            }
1240            else
1241            {
1242                if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageMinKey), &number) )
1243                {
1244                    if ( number < fElements[index].usageMin )
1245                        continue;
1246
1247                    matchingUsageMin = number;
1248                    isMatchingUsageMin = true;
1249                }
1250
1251                if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageMaxKey), &number) )
1252                {
1253                    if ( number > fElements[index].usageMax )
1254                        continue;
1255
1256                    matchingUsageMax = number;
1257                    isMatchingUsageMax = true;
1258                }
1259            }
1260
1261            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsagePageKey), &number) &&
1262                (number != fElements[index].usagePage))
1263                continue;
1264
1265            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementMinKey), &number) &&
1266                ((int32_t)number != fElements[index].min))
1267                continue;
1268
1269            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementMaxKey), &number) &&
1270                ((int32_t)number != fElements[index].max))
1271                continue;
1272
1273            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementScaledMinKey), &number) &&
1274                ((int32_t)number != fElements[index].scaledMin))
1275                continue;
1276
1277            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementScaledMaxKey), &number) &&
1278                ((int32_t)number != fElements[index].scaledMax))
1279                continue;
1280
1281            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementSizeKey), &number) &&
1282                (number != fElements[index].size))
1283                continue;
1284
1285            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportSizeKey), &number) &&
1286                (number != fElements[index].reportSize))
1287                continue;
1288
1289            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportCountKey), &number) &&
1290                (number != fElements[index].reportCount))
1291                continue;
1292
1293            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsRelativeKey), &number) &&
1294                (number != ((fElements[index].flags & kHIDDataRelativeBit) == kHIDDataRelative)))
1295                continue;
1296
1297            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsWrappingKey), &number) &&
1298                (number != ((fElements[index].flags & kHIDDataWrapBit) == kHIDDataWrap)))
1299                continue;
1300
1301            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsNonLinearKey), &number) &&
1302                (number != ((fElements[index].flags & kHIDDataNonlinearBit) == kHIDDataNonlinear)))
1303                continue;
1304
1305            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementHasPreferredStateKey), &number) &&
1306                (number != ((fElements[index].flags & kHIDDataNoPreferredBit) != kHIDDataNoPreferred)))
1307                continue;
1308
1309            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementHasNullStateKey), &number) &&
1310                (number != ((fElements[index].flags & kHIDDataNullStateBit) == kHIDDataNullState)))
1311                continue;
1312
1313            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsArrayKey), &number) &&
1314                (number != ((fElements[index].flags & kHIDDataArrayBit) == kHIDDataArray)))
1315                continue;
1316
1317            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUnitKey), &number) &&
1318                (number != fElements[index].unit))
1319                continue;
1320
1321            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUnitExponentKey), &number) &&
1322                (number != fElements[index].unitExponent))
1323                continue;
1324
1325            if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementDuplicateIndexKey), &number) )
1326            {
1327                if ( !isDuplicateRoot )
1328                    continue;
1329
1330                matchingDupIndex   = number;
1331                isMatchingDupIndex = true;
1332            }
1333        }
1334
1335        uint32_t rangeIndex = 0;
1336        uint32_t usageIndex = 0;
1337        uint32_t duplicateIndex = 0;
1338
1339        while ((fElements[index].cookieMin+rangeIndex)<= fElements[index].cookieMax)
1340        {
1341            // Break out once we are out of the usage range
1342            if (isMatchingUsageMax && (matchingUsageMax < (fElements[index].usageMin+usageIndex)))
1343                break;
1344
1345            // Break out once we are out of the cookie range
1346            if (isMatchingCookieMax && (matchingCookieMax < (fElements[index].cookieMin+rangeIndex)))
1347                break;
1348
1349            // create guy
1350            if ((!isMatchingCookieMin || (isMatchingCookieMin && (matchingCookieMin <= (fElements[index].cookieMin+rangeIndex)))) &&
1351                (!isMatchingUsageMin || (isMatchingUsageMin && (matchingUsageMin <= (fElements[index].usageMin+usageIndex)))) &&
1352                // The container element is always going to be the first
1353                // element in a duplicate range and should be ignored when
1354                // matching on a specific index.
1355                (!isMatchingDupIndex ||
1356                    (((fElements[index].cookieMin+rangeIndex) != fElements[index].cookieMin) &&
1357                    isMatchingDupIndex && (matchingDupIndex == (fElements[index].duplicateIndex+duplicateIndex)))))
1358            {
1359                isElementCached = false;
1360                elementType = createElement(fElementData, &fElements[index], (fElements[index].duplicateValueSize&&!isDuplicateRoot) ? duplicateIndex : rangeIndex, parentElement, elementCache, &isElementCached, options);
1361
1362                if ( elementType )
1363                {
1364                    CFArrayAppendValue(tempElements, elementType);
1365                    CFRelease(elementType);
1366
1367					// RY: Adding a non-cached collection requires digging for the sub elements
1368                    // Ideally, I would like to be able to generate these objects only when
1369                    // requested via CFDictionaryGetValue on kIOHIDElementKey.  Unfortunately,
1370                    // CF does not provide a callback method for CFDictionaryGetValue.  There
1371                    // are ways to work with the CFEqual callback, but you need to handle
1372                    // recursively calling back into yourself on a SetValue.  Spoke to CTP on
1373                    // CF team and requested the ability to have a faulting CFDictionary.  This
1374                    // appears to be desired by other teams as well and is planned for Leopard.
1375                    // Utill then, just populate like normal.
1376                    if ((CFDictionaryGetTypeID()==CFGetTypeID(elementType)) && !isElementCached && (fElements[index].type==kIOHIDElementTypeCollection))
1377                    {
1378                        CFMutableDictionaryRef tempMatchingDict;
1379                        tempMatchingDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1380
1381                        if ( tempMatchingDict )
1382                        {
1383                            CFArrayRef tempSubElements = 0;
1384
1385                            setElementDictIntValue(tempMatchingDict, CFSTR(kIOHIDElementCollectionCookieKey), fElements[index].cookieMin+rangeIndex);
1386                            copyMatchingElements(tempMatchingDict, &tempSubElements, elementType, elementCache, options);
1387
1388                            if (tempSubElements)
1389                            {
1390                                CFDictionarySetValue((CFMutableDictionaryRef)elementType, CFSTR(kIOHIDElementKey), tempSubElements);
1391                                CFRelease(tempSubElements);
1392                            }
1393
1394                            CFRelease(tempMatchingDict);
1395                        }
1396                    }
1397                }
1398
1399				// Matched on duplicate index so we can break out of the loop
1400				if ( isMatchingDupIndex )
1401                    break;
1402
1403                // Break out of both loops if we are looking for a single cookie
1404                if (isMatchingCookieMin && (matchingCookieMin == fElements[index].cookieMin) &&
1405                    isMatchingCookieMax && (matchingCookieMax == matchingCookieMin))
1406                    goto FINISH_ELEMENT_SEARCH;
1407            }
1408
1409            rangeIndex++;
1410
1411            if ((fElements[index].usageMin+usageIndex) != fElements[index].usageMax )
1412                 usageIndex++;
1413
1414            // if a duplicate adjust the other stuff as well
1415            if ( fElements[index].duplicateValueSize && !isDuplicateRoot)
1416                duplicateIndex++;
1417
1418            isDuplicateRoot = false;
1419        }
1420    }
1421
1422FINISH_ELEMENT_SEARCH:
1423    *elements = tempElements;
1424
1425    if (CFArrayGetCount(*elements) == 0)
1426    {
1427        CFRelease(*elements);
1428        *elements = 0;
1429    }
1430
1431    return kIOReturnSuccess;
1432}
1433
1434IOReturn IOHIDDeviceClass::setInterruptReportCallback(uint8_t * report, CFIndex reportLength, IOHIDReportCallback callback, void * refcon, IOOptionBits options)
1435
1436{
1437    IOReturn ret = kIOReturnSuccess;
1438
1439    fInputReportCallback 	= callback;
1440    fInputReportRefcon		= refcon;
1441    fInputReportBuffer		= report;
1442    fInputReportBufferSize	= reportLength;
1443    fInputReportOptions     = options;
1444
1445    // Lazy set up of the queue.
1446    if ( !fReportHandlerQueue )
1447    {
1448		fReportHandlerQueue = createQueue(true);
1449
1450        ret = fReportHandlerQueue->create(0, 8);
1451
1452        if (ret != kIOReturnSuccess)
1453            goto SET_REPORT_HANDLER_CLEANUP;
1454
1455        for (uint32_t i=0; i<fReportHandlerElementCount; i++)
1456        {
1457            ret = fReportHandlerQueue->addElement(getElement((IOHIDElementCookie)fReportHandlerElements[i].cookieMin), 0);
1458
1459            if (ret != kIOReturnSuccess)
1460                goto SET_REPORT_HANDLER_CLEANUP;
1461        }
1462
1463
1464		if ( fAsyncPort && fIsOpen )
1465		{
1466			ret = finishReportHandlerQueueSetup();
1467			if (ret != kIOReturnSuccess)
1468				goto SET_REPORT_HANDLER_CLEANUP;
1469		}
1470    }
1471
1472    return kIOReturnSuccess;
1473
1474SET_REPORT_HANDLER_CLEANUP:
1475    delete fReportHandlerQueue;
1476    fReportHandlerQueue = 0;
1477
1478    return ret;
1479}
1480
1481IOReturn IOHIDDeviceClass::finishReportHandlerQueueSetup()
1482{
1483	IOReturn ret = kIOReturnError;
1484
1485	if ( fReportHandlerQueue )
1486	{
1487		do {
1488			ret = fReportHandlerQueue->setEventCallback(_hidReportHandlerCallback, this);
1489
1490			if (ret != kIOReturnSuccess) break;
1491
1492			ret = fReportHandlerQueue->setAsyncPort(IONotificationPortGetMachPort(fAsyncPort));
1493
1494			if (ret != kIOReturnSuccess) break;
1495
1496			ret = fReportHandlerQueue->start();
1497
1498			if (ret != kIOReturnSuccess) break;
1499
1500		} while ( false );
1501	}
1502	return ret;
1503}
1504
1505void IOHIDDeviceClass::_cfmachPortCallback(CFMachPortRef cfPort, mach_msg_header_t *msg, CFIndex size, void *info)
1506{
1507    mach_msg_header_t *			msgh = (mach_msg_header_t *)msg;
1508	IOHIDDeviceClass *			self = (IOHIDDeviceClass *) info;
1509
1510	if ( !self )
1511		return;
1512
1513    if( msgh->msgh_id == kOSNotificationMessageID)
1514		IODispatchCalloutFromMessage(cfPort, msg, info);
1515	else if ( self->fReportHandlerQueue )
1516		IOHIDQueueClass::queueEventSourceCallback(cfPort, msg, size, self->fReportHandlerQueue);
1517}
1518
1519void IOHIDDeviceClass::_hidReportHandlerCallback(void * refcon, IOReturn result, void * sender __unused)
1520{
1521    IOHIDValueRef           event;
1522    IOHIDDeviceClass *		self = (IOHIDDeviceClass *)refcon;
1523    IOHIDQueueClass *		queue = self->fReportHandlerQueue;
1524    uint32_t                value, size = 0;
1525
1526    if (!self || !self->fIsOpen)
1527        return;
1528
1529    while ((result = queue->copyNextEventValue( &event, 0, 0)) == kIOReturnSuccess)
1530    {
1531        if (IOHIDValueGetBytePtr(event) && IOHIDValueGetLength(event))
1532        {
1533            size = min(self->fInputReportBufferSize, IOHIDValueGetLength(event));
1534            bcopy(IOHIDValueGetBytePtr(event), self->fInputReportBuffer, size);
1535        }
1536
1537        if (self->fInputReportCallback)
1538            (self->fInputReportCallback)(
1539                                        self->fInputReportRefcon,
1540                                        result,
1541                                        &(self->fHIDDevice),
1542                                        kIOHIDReportTypeInput,
1543                                        IOHIDElementGetReportID(IOHIDValueGetElement(event)),
1544                                        self->fInputReportBuffer,
1545                                        size);
1546
1547        CFRelease(event);
1548    }
1549}
1550
1551
1552void
1553IOHIDDeviceClass::_hidReportCallback(void *refcon, IOReturn result, uint32_t bufferSize)
1554{
1555    IOHIDReportRefCon *hidRefcon = (IOHIDReportRefCon *)refcon;
1556
1557    if (!hidRefcon || !hidRefcon->callback)
1558        return;
1559
1560    ((IOHIDReportCallback)hidRefcon->callback)( hidRefcon->callbackRefcon,
1561                                                result,
1562                                                hidRefcon->sender,
1563                                                hidRefcon->type,
1564                                                hidRefcon->reportID,
1565                                                hidRefcon->buffer,
1566                                                bufferSize);
1567
1568    free(hidRefcon);
1569}
1570
1571IOReturn IOHIDDeviceClass::startAllQueues()
1572{
1573    IOReturn ret = kIOReturnSuccess;
1574
1575    if ( fQueues )
1576    {
1577        int			queueCount = CFSetGetCount(fQueues);
1578        IOHIDQueueClass **	queues = NULL;
1579
1580        queues = (IOHIDQueueClass **)malloc(sizeof(IOHIDQueueClass *) * queueCount);
1581
1582        CFSetGetValues(fQueues, (const void **)queues);
1583
1584        for (int i=0; queues && i<queueCount; i++)
1585        {
1586            ret = queues[i]->start();
1587        }
1588
1589        if (queues)
1590            free(queues);
1591
1592    }
1593
1594    return ret;
1595}
1596
1597IOReturn IOHIDDeviceClass::stopAllQueues()
1598{
1599    IOReturn ret = kIOReturnSuccess;
1600
1601    if ( fQueues )
1602    {
1603        int			queueCount = CFSetGetCount(fQueues);
1604        IOHIDQueueClass **	queues	= NULL;
1605
1606        queues = (IOHIDQueueClass **)malloc(sizeof(IOHIDQueueClass *) * queueCount);
1607
1608        CFSetGetValues(fQueues, (const void **)queues);
1609
1610        for (int i=0; queues && i<queueCount && ret==kIOReturnSuccess; i++)
1611        {
1612            ret = queues[i]->stop();
1613        }
1614
1615        if (queues)
1616            free(queues);
1617    }
1618
1619    return ret;
1620}
1621
1622IOCFPlugInInterface IOHIDDeviceClass::sIOCFPlugInInterfaceV1 =
1623{
1624    0,
1625    &IOHIDIUnknown::genericQueryInterface,
1626    &IOHIDIUnknown::genericAddRef,
1627    &IOHIDIUnknown::genericRelease,
1628    1, 0,	// version/revision
1629    &IOHIDDeviceClass::_probe,
1630    &IOHIDDeviceClass::_start,
1631    &IOHIDDeviceClass::_stop
1632};
1633
1634IOHIDDeviceDeviceInterface IOHIDDeviceClass::sHIDDeviceInterfaceV2 =
1635{
1636    0,
1637    &IOHIDIUnknown::genericQueryInterface,
1638    &IOHIDIUnknown::genericAddRef,
1639    &IOHIDIUnknown::genericRelease,
1640    &IOHIDDeviceClass::_open,
1641    &IOHIDDeviceClass::_close,
1642    &IOHIDDeviceClass::_getProperty,
1643    &IOHIDDeviceClass::_setProperty,
1644    &IOHIDDeviceClass::_getAsyncEventSource,
1645    &IOHIDDeviceClass::_copyMatchingElements,
1646    &IOHIDDeviceClass::_setElementValue,
1647    &IOHIDDeviceClass::_getElementValue,
1648    &IOHIDDeviceClass::_setInterruptReportCallback,
1649    &IOHIDDeviceClass::_setReport,
1650    &IOHIDDeviceClass::_getReport
1651};
1652
1653// Methods for routing iocfplugin interface
1654IOReturn IOHIDDeviceClass:: _probe(void *self, CFDictionaryRef propertyTable, io_service_t inService, SInt32 *order)
1655    { return getThis(self)->probe(propertyTable, inService, order); }
1656
1657IOReturn IOHIDDeviceClass::_start(void *self, CFDictionaryRef propertyTable, io_service_t inService)
1658    { return getThis(self)->start(propertyTable, inService); }
1659
1660IOReturn IOHIDDeviceClass::_stop(void *self)
1661    { return getThis(self)->close(); }
1662
1663IOReturn IOHIDDeviceClass::_open(void * self, IOOptionBits options)
1664{ return getThis(self)->open(options); }
1665
1666IOReturn IOHIDDeviceClass::_close(void * self, IOOptionBits options)
1667{ return getThis(self)->close(options); }
1668
1669IOReturn IOHIDDeviceClass::_getProperty(void * self, CFStringRef key, CFTypeRef * pProperty)
1670{ return getThis(self)->getProperty(key, pProperty); }
1671
1672IOReturn IOHIDDeviceClass::_setProperty(void * self, CFStringRef key, CFTypeRef property)
1673{ return getThis(self)->setProperty(key, property); }
1674
1675IOReturn IOHIDDeviceClass::_getAsyncPort(void * self, mach_port_t * port)
1676{ return getThis(self)->getAsyncPort(port); }
1677
1678IOReturn IOHIDDeviceClass::_getAsyncEventSource(void * self, CFTypeRef * pSource)
1679{ return getThis(self)->getAsyncEventSource(pSource); }
1680
1681IOReturn IOHIDDeviceClass::_copyMatchingElements(void * self, CFDictionaryRef matchingDict, CFArrayRef * elements, IOOptionBits options)
1682{
1683    IOReturn            ret     = kIOReturnNoMemory;
1684    IOHIDDeviceClass *  selfRef = getThis(self);
1685
1686	return selfRef->copyMatchingElements(matchingDict, elements, 0, selfRef->fElementCache, options);
1687}
1688
1689IOReturn IOHIDDeviceClass::_setInterruptReportCallback(void * self, uint8_t * report, CFIndex reportLength,
1690                            IOHIDReportCallback callback, void * refcon, IOOptionBits options)
1691{ return getThis(self)->setInterruptReportCallback(report, reportLength, callback, refcon, options); }
1692
1693IOReturn IOHIDDeviceClass::_getReport(void * self, IOHIDReportType reportType, uint32_t reportID, uint8_t * report, CFIndex * pReportLength,
1694                                uint32_t timeout, IOHIDReportCallback callback, void * refcon, IOOptionBits options)
1695{ return getThis(self)->getReport(reportType, reportID, report, pReportLength, timeout, callback, refcon, options);}
1696
1697IOReturn IOHIDDeviceClass::_setReport(void * self, IOHIDReportType reportType, uint32_t reportID, const uint8_t * report, CFIndex reportLength,
1698                                uint32_t timeout, IOHIDReportCallback callback, void * refcon, IOOptionBits options)
1699{ return getThis(self)->setReport(reportType, reportID, report, reportLength, timeout, callback, refcon, options);}
1700
1701IOReturn IOHIDDeviceClass::_getElementValue(void * self, IOHIDElementRef element, IOHIDValueRef * pEvent,
1702                                uint32_t timeout, IOHIDValueCallback callback, void * refcon, IOOptionBits options)
1703{ return getThis(self)->getElementValue(element, pEvent, timeout, callback, refcon, options); };
1704
1705IOReturn IOHIDDeviceClass::_setElementValue(void * self, IOHIDElementRef element, IOHIDValueRef event,
1706                                uint32_t timeout, IOHIDValueCallback callback, void * refcon, IOOptionBits options)
1707{ return getThis(self)->setElementValue(element, event, timeout, callback, refcon, options);};
1708
1709
1710#define SWAP_KERNEL_ELEMENT(element)                                        \
1711{                                                                           \
1712    element.cookieMin           = OSSwapInt32(element.cookieMin);           \
1713    element.cookieMax           = OSSwapInt32(element.cookieMax);           \
1714    element.parentCookie        = OSSwapInt32(element.parentCookie);        \
1715    element.type                = OSSwapInt32(element.type);                \
1716    element.collectionType      = OSSwapInt32(element.collectionType);      \
1717    element.flags               = OSSwapInt32(element.flags);               \
1718    element.usagePage           = OSSwapInt32(element.usagePage);           \
1719    element.usageMin            = OSSwapInt32(element.usageMin);            \
1720    element.usageMax            = OSSwapInt32(element.usageMax);            \
1721    element.min                 = OSSwapInt32(element.min);                 \
1722    element.max                 = OSSwapInt32(element.max);                 \
1723    element.scaledMin           = OSSwapInt32(element.scaledMin);           \
1724    element.scaledMax           = OSSwapInt32(element.scaledMax);           \
1725    element.size                = OSSwapInt32(element.size);                \
1726    element.reportSize          = OSSwapInt32(element.reportSize);          \
1727    element.reportCount         = OSSwapInt32(element.reportCount);         \
1728    element.reportID            = OSSwapInt32(element.reportID);            \
1729    element.unit                = OSSwapInt32(element.unit);                \
1730    element.unitExponent        = OSSwapInt32(element.unitExponent);        \
1731    element.duplicateValueSize  = OSSwapInt32(element.duplicateValueSize);  \
1732    element.bytes               = OSSwapInt32(element.bytes);               \
1733    element.valueLocation       = OSSwapInt32(element.valueLocation);       \
1734    element.valueSize           = OSSwapInt32(element.valueSize);           \
1735}
1736
1737IOReturn IOHIDDeviceClass::buildElements( uint32_t type, CFMutableDataRef * pDataRef, IOHIDElementStruct ** buffer, uint32_t * count )
1738{
1739    size_t    size;
1740    IOReturn    kr;
1741
1742
1743    size = sizeof(IOHIDElementStruct) * *count;
1744
1745    *pDataRef = CFDataCreateMutable(kCFAllocatorDefault, size);
1746
1747    if (!*pDataRef)
1748        return kIOReturnNoMemory;
1749
1750    // count the number of leaves and allocate
1751    *buffer = (IOHIDElementStruct*)CFDataGetMutableBytePtr(*pDataRef);
1752
1753    HIDLog ("IOHIDDeviceClass::buildElements: type=%d *buffer=%4.4x *count=%d size=%d\n", type, *buffer, *count, size);
1754
1755    bzero(*buffer, size);
1756
1757    uint64_t input = type;
1758
1759    kr = IOConnectCallMethod(fConnection, kIOHIDLibUserClientGetElements, &input, 1, 0, 0, 0, 0, *buffer, &size);
1760
1761    *count = size / sizeof(IOHIDElementStruct);
1762
1763    ROSETTA_ONLY(
1764        for ( uint32_t i=0; i<*count; i++)
1765        {
1766            SWAP_KERNEL_ELEMENT((*buffer)[i]);
1767        }
1768    );
1769
1770#if 0
1771    for (uint32_t index = 0; index < *count; index++)
1772    {
1773        HIDLog ("IOHIDDeviceClass::buildElements: CookieMin=%d CookieMax=%d Min=%d Max=%d UsagePage=0x%x UsageMin=0x%x UsageMax=0x%x Type=%d\n", (*buffer)[index].cookieMin, (*buffer)[index].cookieMax, (*buffer)[index].min, (*buffer)[index].max, (*buffer)[index].usagePage, (*buffer)[index].usageMin, (*buffer)[index].usageMax, (*buffer)[index].type);
1774    }
1775#endif
1776
1777    return kr;
1778}
1779
1780IOHIDElementRef IOHIDDeviceClass::getElement(IOHIDElementCookie cookie)
1781{
1782    IOHIDElementStruct *elementStruct = 0;
1783    IOHIDElementRef     element=NULL;
1784    CFDataRef           dataRef=NULL;
1785    uint32_t            index=0;
1786
1787    if ( getElementStructPtr(cookie, &elementStruct, &index, &dataRef) )
1788    {
1789        element = (IOHIDElementRef)createElement(dataRef, elementStruct, index, 0, fElementCache);
1790
1791        if (element) CFRelease(element); // element should be cached so we can release it
1792    }
1793
1794    return  element;
1795}
1796
1797uint32_t IOHIDDeviceClass::getElementByteSize(IOHIDElementCookie elementCookie)
1798{
1799    uint32_t size = 0;
1800    IOHIDElementStruct element;
1801
1802    if (getElementStruct(elementCookie, &element))
1803            size = element.bytes;
1804
1805    return size;
1806}
1807
1808bool IOHIDDeviceClass::getElementStructPtr(IOHIDElementCookie elementCookie, IOHIDElementStruct ** ppElementStruct, uint32_t * pIndex, CFDataRef * pData)
1809{
1810    uint32_t cookieIndex = 0;
1811    uint32_t index = 0;
1812    for (index = 0; index < fElementCount; index++)
1813    {
1814        if ( ((uint32_t) elementCookie >= fElements[index].cookieMin) && ((uint32_t) elementCookie <= fElements[index].cookieMax) )
1815        {
1816            cookieIndex = 0;
1817            while ( (fElements[index].cookieMin != fElements[index].cookieMax) && ((fElements[index].cookieMin + cookieIndex) != (uint32_t)elementCookie) )
1818                cookieIndex++;
1819
1820            if ( ppElementStruct )
1821                *ppElementStruct = &fElements[index];
1822
1823            if ( pIndex )
1824                *pIndex = cookieIndex;
1825
1826            if ( pData )
1827                *pData = fElementData;
1828            return true;
1829        }
1830    }
1831    cookieIndex = 0;
1832    for (index = 0; index < fReportHandlerElementCount; index++)
1833    {
1834        if ( ((uint32_t) elementCookie >= fReportHandlerElements[index].cookieMin) && ((uint32_t) elementCookie <= fReportHandlerElements[index].cookieMax) )
1835        {
1836            if ( ppElementStruct )
1837                *ppElementStruct = &fReportHandlerElements[index];
1838
1839            if ( pIndex )
1840                *pIndex = cookieIndex;
1841
1842            if ( pData )
1843                *pData = fReportHandlerElementData;
1844            return true;
1845        }
1846    }
1847    return false;
1848}
1849
1850bool IOHIDDeviceClass::getElementStruct(IOHIDElementCookie elementCookie, IOHIDElementStruct * elementStruct)
1851{
1852    IOHIDElementStruct * pElementStruct = 0;
1853
1854    if (getElementStructPtr(elementCookie, &pElementStruct))
1855    {
1856        if (pElementStruct)
1857        {
1858            IOHIDElementStruct tempElement = *pElementStruct;
1859
1860            while ( tempElement.cookieMin != (uint32_t)elementCookie )
1861            {
1862                tempElement.cookieMin++;
1863
1864                if (tempElement.duplicateValueSize)
1865                    tempElement.valueLocation -= tempElement.duplicateValueSize;
1866                else
1867                    tempElement.valueLocation -= tempElement.valueSize;
1868            }
1869
1870            // if a duplicate adjust the other stuff as well
1871            if ( tempElement.duplicateValueSize && (tempElement.cookieMin != pElementStruct->cookieMin))
1872            {
1873                tempElement.size = tempElement.reportSize;
1874                tempElement.bytes = (tempElement.size + 7) / 8;
1875            }
1876
1877            if (elementStruct)
1878                *elementStruct = tempElement;
1879        }
1880
1881        return true;
1882    }
1883
1884    return false;
1885}
1886
1887//****************************************************************************************************
1888// Class:       IOHIDObsoleteDeviceClass
1889// Subclasses:  IOHIDDeviceClass
1890//****************************************************************************************************
1891IOCFPlugInInterface ** IOHIDObsoleteDeviceClass::alloc()
1892{
1893    IOHIDObsoleteDeviceClass *me;
1894
1895    me = new IOHIDObsoleteDeviceClass;
1896    if (me)
1897        return (IOCFPlugInInterface **) &me->iunknown.pseudoVTable;
1898    else
1899        return 0;
1900}
1901
1902IOHIDObsoleteDeviceClass::IOHIDObsoleteDeviceClass() : IOHIDDeviceClass()
1903{
1904    fHIDDevice.pseudoVTable = (IUnknownVTbl *)  &sHIDDeviceInterfaceV122;
1905    fHIDDevice.obj = this;
1906	fInputReportContext = NULL;
1907}
1908
1909//====================================================================================================
1910// IOHIDObsoleteDeviceClass::IOHIDDeviceInterfaceV1 Static Methods
1911//====================================================================================================
1912
1913IOHIDDeviceInterface122 IOHIDObsoleteDeviceClass::sHIDDeviceInterfaceV122 =
1914{
1915    0,
1916    &IOHIDIUnknown::genericQueryInterface,
1917    &IOHIDIUnknown::genericAddRef,
1918    &IOHIDIUnknown::genericRelease,
1919    &IOHIDObsoleteDeviceClass::_createAsyncEventSource,
1920    &IOHIDObsoleteDeviceClass::_getAsyncEventSource,
1921    &IOHIDDeviceClass::_getAsyncPort,
1922    &IOHIDObsoleteDeviceClass::_getAsyncPort,
1923    &IOHIDObsoleteDeviceClass::_open,
1924    &IOHIDObsoleteDeviceClass::_close,
1925    &IOHIDObsoleteDeviceClass::_setRemovalCallback,
1926    &IOHIDObsoleteDeviceClass::_getElementValue,
1927    &IOHIDObsoleteDeviceClass::_setElementValue,
1928    &IOHIDObsoleteDeviceClass::_queryElementValue,
1929    &IOHIDObsoleteDeviceClass::_startAllQueues,
1930    &IOHIDObsoleteDeviceClass::_stopAllQueues,
1931    &IOHIDObsoleteDeviceClass::_allocQueue,
1932    &IOHIDObsoleteDeviceClass::_allocOutputTransaction,
1933    &IOHIDObsoleteDeviceClass::_setReport,
1934    &IOHIDObsoleteDeviceClass::_getReport,
1935    &IOHIDObsoleteDeviceClass::_copyMatchingElements,
1936    &IOHIDObsoleteDeviceClass::_setInterruptReportHandlerCallback
1937};
1938
1939//====================================================================================================
1940// IOHIDObsoleteDeviceClass::IOHIDDeviceInterfaceV1 Static Methods
1941//====================================================================================================
1942IOReturn IOHIDObsoleteDeviceClass::_createAsyncEventSource(void * self, CFRunLoopSourceRef * pSource)
1943{
1944    return getThis(self)->createAsyncEventSource(pSource);
1945}
1946
1947CFRunLoopSourceRef IOHIDObsoleteDeviceClass::_getAsyncEventSource(void *self)
1948{
1949    CFTypeRef source = NULL;
1950    getThis(self)->getAsyncEventSource(&source);
1951    return (CFRunLoopSourceRef)source;
1952}
1953
1954mach_port_t IOHIDObsoleteDeviceClass::_getAsyncPort(void *self)
1955{
1956    mach_port_t port = MACH_PORT_NULL;
1957    getThis(self)->getAsyncPort(&port);
1958    return port;
1959}
1960
1961IOReturn IOHIDObsoleteDeviceClass::_close(void *self)
1962{
1963    return getThis(self)->close();
1964}
1965
1966IOReturn IOHIDObsoleteDeviceClass::_setRemovalCallback(void * self, IOHIDCallbackFunction callback, void * target, void * refcon)
1967{
1968    return getThis(self)->setRemovalCallback (callback, target, refcon);
1969}
1970
1971IOReturn IOHIDObsoleteDeviceClass::_getElementValue(void * self, IOHIDElementCookie elementCookie, IOHIDEventStruct * valueEvent)
1972{
1973    return getThis(self)->getElementValue (elementCookie, valueEvent);
1974}
1975
1976IOReturn IOHIDObsoleteDeviceClass::_setElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon)
1977{
1978    return getThis(self)->setElementValue(cookie, pEvent, timeout, callback, target, refcon);
1979}
1980
1981IOReturn IOHIDObsoleteDeviceClass::_queryElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon)
1982{
1983    return getThis(self)->queryElementValue (cookie, pEvent, timeout, callback, target, refcon);
1984}
1985
1986IOReturn IOHIDObsoleteDeviceClass::_startAllQueues(void * self)
1987{
1988    return getThis(self)->startAllQueues ();
1989}
1990
1991IOReturn IOHIDObsoleteDeviceClass::_stopAllQueues(void * self)
1992{
1993    return getThis(self)->stopAllQueues ();
1994}
1995
1996IOHIDQueueInterface ** IOHIDObsoleteDeviceClass::_allocQueue(void *self)
1997{
1998    return getThis(self)->allocQueue ();
1999}
2000
2001IOHIDOutputTransactionInterface ** IOHIDObsoleteDeviceClass::_allocOutputTransaction (void *self)
2002{
2003    return getThis(self)->allocOutputTransaction();
2004}
2005
2006IOReturn IOHIDObsoleteDeviceClass::_setReport (void * self, IOHIDReportType type, uint32_t id, void * report, uint32_t length, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2007{
2008    return getThis(self)->setReport(type, id, report, length, timeout, callback, target, refcon);
2009}
2010
2011IOReturn IOHIDObsoleteDeviceClass::_getReport (void * self, IOHIDReportType type, uint32_t id, void * report, uint32_t * pLength, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2012{
2013    return getThis(self)->getReport(type, id, report, pLength, timeout, callback, target, refcon);
2014}
2015
2016IOReturn IOHIDObsoleteDeviceClass::_copyMatchingElements(void * self, CFDictionaryRef matchingDict, CFArrayRef *elements)
2017{
2018    IOReturn ret = kIOReturnNoMemory;
2019    CFMutableDictionaryRef cache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2020
2021    if ( cache )
2022    {
2023        ret = getThis(self)->copyMatchingElements(matchingDict, elements, 0, cache, kCreateMatchingHIDElementsWithDictionaries);
2024        CFRelease(cache);
2025    }
2026
2027    return ret;
2028}
2029
2030IOReturn IOHIDObsoleteDeviceClass::_setInterruptReportHandlerCallback(void * self, void * report, uint32_t length, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2031{
2032    return getThis(self)->setInterruptReportHandlerCallback(report, length, callback, target, refcon);
2033}
2034
2035IOHIDQueueClass * IOHIDObsoleteDeviceClass::createQueue(bool reportHandler)
2036{
2037    IOHIDObsoleteQueueClass * newQueue = new IOHIDObsoleteQueueClass;
2038
2039    // attach the queue to us
2040    attachQueue (newQueue, reportHandler);
2041
2042	return newQueue;
2043}
2044
2045HRESULT IOHIDObsoleteDeviceClass::queryInterfaceTransaction (CFUUIDRef uuid __unused, void **ppv)
2046{
2047    HRESULT res = S_OK;
2048
2049    IOHIDOutputTransactionClass * transaction = new IOHIDOutputTransactionClass;
2050
2051    transaction->setDirection(kIOHIDTransactionDirectionTypeOutput);
2052
2053    attachTransaction(transaction);
2054
2055    *ppv = transaction->getInterfaceMap();
2056
2057    return res;
2058}
2059
2060
2061HRESULT IOHIDObsoleteDeviceClass::queryInterface(REFIID iid, void **ppv)
2062{
2063    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
2064    HRESULT res = S_OK;
2065
2066    if (CFEqual(uuid, kIOHIDQueueInterfaceID))
2067        res = queryInterfaceQueue(uuid, ppv);
2068    else if (CFEqual(uuid, kIOHIDOutputTransactionInterfaceID))
2069        res = queryInterfaceTransaction(uuid, ppv);
2070    else if (CFEqual(uuid, kIOHIDDeviceInterfaceID) || CFEqual(uuid, kIOHIDDeviceInterfaceID121) || CFEqual(uuid, kIOHIDDeviceInterfaceID122))
2071    {
2072        *ppv = &fHIDDevice;
2073        addRef();
2074    }
2075    else {
2076        res = IOHIDDeviceClass::queryInterface(iid, ppv);
2077    }
2078
2079    if (!*ppv)
2080        res = E_NOINTERFACE;
2081
2082    CFRelease(uuid);
2083    return res;
2084}
2085
2086IOReturn IOHIDObsoleteDeviceClass::createAsyncEventSource(CFRunLoopSourceRef * pSource)
2087{
2088    IOReturn ret = IOHIDDeviceClass::getAsyncEventSource((CFTypeRef*)pSource);
2089
2090    if ( ret == kIOReturnSuccess && pSource && *pSource )
2091        CFRetain(*pSource);
2092
2093    return ret;
2094}
2095
2096
2097IOReturn IOHIDObsoleteDeviceClass::setRemovalCallback(IOHIDCallbackFunction removalCallback, void * removalTarget, void * removalRefcon)
2098{
2099	IOReturn ret = kIOReturnSuccess;
2100
2101	if (!fAsyncPrivateDataRef)
2102	{
2103
2104		fAsyncPrivateDataRef = (MyPrivateData *)malloc(sizeof(MyPrivateData));
2105		bzero(fAsyncPrivateDataRef, sizeof(MyPrivateData));
2106
2107		fAsyncPrivateDataRef->self		= this;
2108
2109        if (!fAsyncPort) {
2110            ret = getAsyncPort(0);
2111            if (kIOReturnSuccess != ret)
2112                return ret;
2113        }
2114
2115		// Register for an interest notification of this device being removed. Use a reference to our
2116		// private data as the refCon which will be passed to the notification callback.
2117		ret = IOServiceAddInterestNotification( fAsyncPort,
2118												fService,
2119												kIOGeneralInterest,
2120												IOHIDDeviceClass::_deviceNotification,
2121												fAsyncPrivateDataRef,
2122												&(fAsyncPrivateDataRef->notification));
2123	}
2124
2125    fRemovalCallback    = removalCallback;
2126    fRemovalTarget      = removalTarget;
2127    fRemovalRefcon      = removalRefcon;
2128
2129    return ret;
2130}
2131
2132IOReturn
2133IOHIDObsoleteDeviceClass::setElementValue(IOHIDElementRef element,
2134                                          IOHIDValueRef event,
2135                                          uint32_t timeout,
2136                                          IOHIDValueCallback callback,
2137                                          void * refcon,
2138                                          IOOptionBits options)
2139{
2140    return IOHIDDeviceClass::setElementValue(element, event, timeout, callback, refcon, options);
2141}
2142
2143IOReturn IOHIDObsoleteDeviceClass::setElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon, IOOptionBits options)
2144{
2145    IOHIDElementRef element = getElement(cookie);
2146    IOHIDValueRef   event   = _IOHIDValueCreateWithStruct(kCFAllocatorDefault, element, pEvent);
2147    IOReturn        kr      = kIOReturnNoMemory;
2148
2149    if ( event )
2150    {
2151        IOHIDValueCallback          valueCallback   = NULL;
2152        IOHIDObsoleteCallbackArgs * valueArgs       = NULL;
2153
2154        if ( callback ) {
2155            valueCallback   = IOHIDObsoleteDeviceClass::_elementValueCallback;
2156            valueArgs       = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs));
2157
2158            if ( !valueArgs ) {
2159                CFRelease(event);
2160                return kIOReturnNoMemory;
2161            }
2162
2163            bzero(valueArgs, sizeof(IOHIDObsoleteCallbackArgs));
2164
2165            valueArgs->self     = this;
2166            valueArgs->callback = (void *)callback;
2167            valueArgs->target   = target;
2168            valueArgs->refcon   = refcon;
2169        }
2170
2171        kr = IOHIDDeviceClass::setElementValue(element, event, timeout, valueCallback, valueArgs, options);
2172        CFRelease(event);
2173    }
2174
2175    return kr;
2176}
2177
2178IOReturn IOHIDObsoleteDeviceClass::queryElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon)
2179{
2180    IOHIDValueRef   event = 0;
2181    IOReturn        kr = kIOReturnBadArgument;
2182
2183    if ( pEvent )
2184    {
2185        IOHIDValueCallback       valueCallback   = NULL;
2186        IOHIDObsoleteCallbackArgs *     valueArgs       = NULL;
2187
2188        if ( callback ) {
2189            valueCallback   = IOHIDObsoleteDeviceClass::_elementValueCallback;
2190            valueArgs       = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs));
2191
2192            if ( !valueArgs )
2193                return kIOReturnNoMemory;
2194
2195            bzero(valueArgs, sizeof(IOHIDObsoleteCallbackArgs));
2196
2197            valueArgs->self     = this;
2198            valueArgs->callback = (void *)callback;
2199            valueArgs->target   = target;
2200            valueArgs->refcon   = refcon;
2201        }
2202
2203        kr = IOHIDDeviceClass::getElementValue(getElement(cookie), &event, timeout, valueCallback, valueArgs, kHIDGetElementValueForcePoll);
2204
2205        if ((kr==kIOReturnSuccess) && event)
2206        {
2207            uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event));
2208
2209            pEvent->type                    = IOHIDElementGetType(IOHIDValueGetElement(event));
2210            pEvent->elementCookie           = IOHIDElementGetCookie(IOHIDValueGetElement(event));
2211            *(UInt64 *)& pEvent->timestamp  = IOHIDValueGetTimeStamp(event);
2212
2213            if ( length > sizeof(uint32_t) )
2214            {
2215                pEvent->longValueSize = length;
2216                pEvent->longValue     = malloc(length);
2217                bcopy(IOHIDValueGetBytePtr(event), pEvent->longValue, length);
2218            }
2219            else
2220            {
2221                pEvent->longValueSize = 0;
2222                pEvent->longValue     = NULL;
2223                pEvent->value         = IOHIDValueGetIntegerValue(event);
2224            }
2225        }
2226    }
2227
2228    return kr;
2229}
2230
2231IOReturn
2232IOHIDObsoleteDeviceClass::getElementValue(IOHIDElementRef element,
2233                                          IOHIDValueRef * pEvent,
2234                                          uint32_t timeout,
2235                                          IOHIDValueCallback callback,
2236                                          void * refcon,
2237                                          IOOptionBits options)
2238{
2239    return IOHIDDeviceClass::getElementValue(element, pEvent, timeout, callback, refcon, options);
2240}
2241
2242IOReturn IOHIDObsoleteDeviceClass::getElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent)
2243
2244{
2245    IOHIDValueRef   event = 0;
2246    IOReturn        kr = kIOReturnBadArgument;
2247
2248    if ( pEvent )
2249    {
2250        kr = IOHIDDeviceClass::getElementValue(getElement(cookie), &event);
2251
2252        if ((kr==kIOReturnSuccess) && event)
2253        {
2254            uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event));
2255
2256            pEvent->type                    = IOHIDElementGetType(IOHIDValueGetElement(event));
2257            pEvent->elementCookie           = IOHIDElementGetCookie(IOHIDValueGetElement(event));
2258            *(UInt64 *)& pEvent->timestamp  = IOHIDValueGetTimeStamp(event);
2259
2260            if ( length > sizeof(uint32_t) )
2261            {
2262                pEvent->longValueSize = length;
2263                pEvent->longValue     = malloc(length);
2264                bcopy(IOHIDValueGetBytePtr(event), pEvent->longValue, length);
2265            }
2266            else
2267            {
2268                pEvent->longValueSize = 0;
2269                pEvent->longValue     = NULL;
2270                pEvent->value         = IOHIDValueGetIntegerValue(event);
2271            }
2272        }
2273    }
2274
2275    return kr;
2276}
2277
2278IOReturn
2279IOHIDObsoleteDeviceClass::setReport(IOHIDReportType reportType,
2280                           uint32_t reportID,
2281                           const uint8_t * report,
2282                           CFIndex reportLength,
2283                           uint32_t timeout,
2284                           IOHIDReportCallback callback,
2285                           void * refcon,
2286                           IOOptionBits options)
2287{
2288    return IOHIDDeviceClass::setReport(reportType, reportID, report, reportLength, timeout, callback, refcon, options);
2289}
2290
2291IOReturn IOHIDObsoleteDeviceClass::setReport(IOHIDReportType type, uint32_t id, void * report, uint32_t length, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2292{
2293    IOHIDReportCallback         reportCallback  = NULL;
2294    IOHIDObsoleteCallbackArgs * reportContext   = NULL;
2295
2296    if ( callback ) {
2297        reportCallback  = IOHIDObsoleteDeviceClass::_reportCallback;
2298        reportContext   = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs));
2299
2300        if ( !reportContext )
2301            return kIOReturnNoMemory;
2302
2303        bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs));
2304
2305        reportContext->self     = this;
2306        reportContext->callback = (void *)callback;
2307        reportContext->target   = target;
2308        reportContext->refcon   = refcon;
2309    }
2310
2311    return IOHIDDeviceClass::setReport(type, id, (const uint8_t *)report, length, timeout, reportCallback, reportContext);
2312}
2313
2314IOReturn
2315IOHIDObsoleteDeviceClass::getReport(IOHIDReportType reportType,
2316                           uint32_t reportID,
2317                           uint8_t * report,
2318                           CFIndex * pReportLength,
2319                           uint32_t timeout,
2320                           IOHIDReportCallback callback,
2321                           void * refcon,
2322                           IOOptionBits options)
2323{
2324    return IOHIDDeviceClass::getReport(reportType, reportID, report, pReportLength, timeout, callback, refcon, options);
2325}
2326
2327IOReturn IOHIDObsoleteDeviceClass::getReport(IOHIDReportType type, uint32_t id, void * report, uint32_t * pLength, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2328{
2329    IOHIDReportCallback         reportCallback  = NULL;
2330    IOHIDObsoleteCallbackArgs * reportContext   = NULL;
2331
2332    if ( callback ) {
2333        reportCallback  = IOHIDObsoleteDeviceClass::_reportCallback;
2334        reportContext   = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs));
2335
2336        if ( !reportContext )
2337            return kIOReturnNoMemory;
2338
2339        bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs));
2340
2341        reportContext->self     = this;
2342        reportContext->callback = (void *)callback;
2343        reportContext->target   = target;
2344        reportContext->refcon   = refcon;
2345        reportContext->pLength  = pLength;
2346    }
2347
2348    CFIndex pReportLength = pLength ? *pLength : 0;
2349
2350    IOReturn ret = IOHIDDeviceClass::getReport(type, id, (uint8_t *)report, &pReportLength, timeout, reportCallback, reportContext);
2351
2352    if ( pLength )
2353        *pLength = pReportLength;
2354
2355    return ret;
2356}
2357
2358IOReturn IOHIDObsoleteDeviceClass::setInterruptReportHandlerCallback(void * report, uint32_t length, IOHIDReportCallbackFunction callback, void * target, void * refcon)
2359{
2360    IOHIDObsoleteCallbackArgs * reportContext = (IOHIDObsoleteCallbackArgs *)fInputReportContext;
2361
2362    if ( !reportContext ) {
2363        reportContext = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs));
2364
2365        if ( !reportContext )
2366            return kIOReturnNoMemory;
2367
2368        fInputReportContext = reportContext;
2369    }
2370
2371    bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs));
2372
2373    reportContext->self       = this;
2374    reportContext->callback   = (void *)callback;
2375    reportContext->target     = target;
2376    reportContext->refcon     = refcon;
2377
2378    return IOHIDDeviceClass::setInterruptReportCallback((uint8_t*)report, length, IOHIDObsoleteDeviceClass::_reportCallback, reportContext);
2379}
2380
2381void IOHIDObsoleteDeviceClass::_elementValueCallback(void * context, IOReturn result, void * sender, IOHIDValueRef value)
2382{
2383    IOHIDObsoleteCallbackArgs * valueArgs = (IOHIDObsoleteCallbackArgs *)context;
2384
2385    (*(IOHIDElementCallbackFunction)valueArgs->callback)(
2386                            valueArgs->target,
2387                            result,
2388                            valueArgs->refcon,
2389                            sender,
2390                            IOHIDElementGetCookie(IOHIDValueGetElement(value)));
2391
2392    free(context);
2393}
2394
2395void IOHIDObsoleteDeviceClass::_reportCallback(
2396                                        void *                  context,
2397                                        IOReturn                result,
2398                                        void *                  sender,
2399                                        IOHIDReportType         type __unused,
2400                                        uint32_t                reportID __unused,
2401                                        uint8_t *               report __unused,
2402                                        CFIndex                 reportLength)
2403{
2404    IOHIDObsoleteCallbackArgs * args = (IOHIDObsoleteCallbackArgs*)context;
2405
2406    if ( args->pLength )
2407        *(args->pLength) = reportLength;
2408
2409    (*(IOHIDReportCallbackFunction)args->callback)(
2410                        args->target,
2411                        result,
2412                        args->refcon,
2413                        sender,
2414                        reportLength);
2415
2416    if ( args->self->fInputReportContext != context )
2417        free(context);
2418}
2419
2420IOHIDQueueInterface ** IOHIDObsoleteDeviceClass::allocQueue()
2421{
2422    IOHIDQueueInterface **	iohidqueue;
2423    HRESULT 			res;
2424
2425    res = this->queryInterface(CFUUIDGetUUIDBytes(kIOHIDQueueInterfaceID), (void **) &iohidqueue);
2426
2427    return iohidqueue;
2428}
2429
2430IOHIDOutputTransactionInterface ** IOHIDObsoleteDeviceClass::allocOutputTransaction()
2431{
2432    IOHIDOutputTransactionInterface **	iohidoutputtransaction;
2433    HRESULT 				res;
2434
2435    res = this->queryInterface(CFUUIDGetUUIDBytes(kIOHIDOutputTransactionInterfaceID), (void **) &iohidoutputtransaction);
2436
2437    return iohidoutputtransaction;
2438}
2439