1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#define CFRUNLOOP_NEW_API 1
25
26#include <CoreFoundation/CFMachPort.h>
27//#include <IOKit/hid/IOHIDLib.h>
28//#include <unistd.h>
29#include <IOKit/hid/IOHIDValue.h>
30#include "IOHIDQueueClass.h"
31#include "IOHIDLibUserClient.h"
32
33__BEGIN_DECLS
34#include <asl.h>
35#include <IOKit/IODataQueueClient.h>
36#include <mach/mach.h>
37#include <mach/mach_interface.h>
38#include <IOKit/iokitmig.h>
39#include <System/libkern/OSCrossEndian.h>
40__END_DECLS
41
42#define ownerCheck() do {		\
43    if (!fOwningDevice)			\
44	return kIOReturnNoDevice;	\
45} while (0)
46
47#define connectCheck() do {		\
48    if ((!fOwningDevice) ||		\
49    	(!fOwningDevice->fConnection))	\
50	return kIOReturnNoDevice;	\
51} while (0)
52
53#define createdCheck() do {     \
54    if (!fIsCreated)            \
55    return kIOReturnError;      \
56} while (0)
57
58#define openCheck() do {            \
59    if (!fOwningDevice ||           \
60        !fOwningDevice->fIsOpen)    \
61        return kIOReturnNotOpen;    \
62} while (0)
63
64#define terminatedCheck() do {		\
65    if ((!fOwningDevice) ||		\
66         (fOwningDevice->fIsTerminated))\
67        return kIOReturnNotAttached;	\
68} while (0)
69
70#define mostChecks() do {   \
71    ownerCheck();           \
72    connectCheck();			\
73    createdCheck();         \
74    terminatedCheck();      \
75} while (0)
76
77#define allChecks() do {    \
78    mostChecks();           \
79    openCheck();			\
80} while (0)
81
82
83IOHIDQueueClass::IOHIDQueueClass() : IOHIDIUnknown(NULL)
84{
85    fHIDQueue.pseudoVTable = (IUnknownVTbl *)  &sHIDQueueInterfaceV2;
86    fHIDQueue.obj = this;
87
88    fAsyncPort              = MACH_PORT_NULL;
89    fCFMachPort             = NULL;
90    fCFSource               = NULL;
91    fIsCreated              = false;
92    fCreatedFlags           = 0;
93    fQueueRef               = 0;
94    fCreatedDepth           = 0;
95    fQueueEntrySizeChanged  = false;
96    fQueueMappedMemory      = NULL;
97    fQueueMappedMemorySize  = 0;
98    fOwningDevice           = NULL;
99    fEventCallback          = NULL;
100    fEventRefcon            = NULL;
101    fElements               = NULL;
102}
103
104IOHIDQueueClass::~IOHIDQueueClass()
105{
106    if (fIsCreated)
107        dispose();
108
109    if (fElements)
110        CFRelease(fElements);
111
112    // if we are owned, detatch
113    if (fOwningDevice)
114        fOwningDevice->detachQueue(this);
115
116    if (fCFMachPort) {
117        CFMachPortInvalidate(fCFMachPort);
118        CFRelease(fCFMachPort);
119    }
120
121	if (fAsyncPort) {
122        mach_port_mod_refs(mach_task_self(), fAsyncPort, MACH_PORT_RIGHT_RECEIVE, -1);
123    }
124
125    if (fCFSource)
126        CFRelease(fCFSource);
127}
128
129HRESULT IOHIDQueueClass::queryInterface(REFIID iid, void **	ppv)
130{
131    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
132    HRESULT res = S_OK;
133
134    if (CFEqual(uuid, kIOHIDDeviceQueueInterfaceID))
135    {
136        *ppv = getInterfaceMap();
137        addRef();
138    }
139    else {
140        res = fOwningDevice->queryInterface(iid, ppv);
141    }
142
143    if (!*ppv)
144        res = E_NOINTERFACE;
145
146    CFRelease(uuid);
147    return res;
148}
149
150IOReturn IOHIDQueueClass::getAsyncEventSource(CFTypeRef *source)
151{
152    IOReturn ret;
153
154    if (!fAsyncPort) {
155        ret = getAsyncPort(0);
156        if (kIOReturnSuccess != ret)
157            return ret;
158    }
159
160    if ( !fCFMachPort ) {
161        CFMachPortContext   context;
162        Boolean             shouldFreeInfo = FALSE;
163
164        context.version = 1;
165        context.info = this;
166        context.retain = NULL;
167        context.release = NULL;
168        context.copyDescription = NULL;
169
170        fCFMachPort = CFMachPortCreateWithPort(NULL, fAsyncPort,
171                    (CFMachPortCallBack) IOHIDQueueClass::queueEventSourceCallback,
172                    &context, &shouldFreeInfo);
173
174        if ( shouldFreeInfo ) {
175            // The CFMachPort we got might not work, but we'll proceed with it anyway.
176            asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s received an unexpected reused CFMachPort", __func__);
177        }
178
179        if (!fCFMachPort)
180            return kIOReturnNoMemory;
181    }
182
183    if ( !fCFSource ) {
184        fCFSource = CFMachPortCreateRunLoopSource(NULL, fCFMachPort, 0);
185        if (!fCFSource)
186            return kIOReturnNoMemory;
187    }
188
189    if (source)
190        *source = fCFSource;
191
192    return kIOReturnSuccess;
193}
194
195/* CFMachPortCallBack */
196void IOHIDQueueClass::queueEventSourceCallback(CFMachPortRef        cfPort __unused,
197                                               mach_msg_header_t    *msg __unused,
198                                               CFIndex              size __unused,
199                                               void                 *info)
200{
201
202    IOHIDQueueClass *queue = (IOHIDQueueClass *)info;
203
204    if ( queue ) {
205        if ( queue->fEventCallback ) {
206
207            (queue->fEventCallback)(queue->fEventRefcon,
208                            kIOReturnSuccess,
209                            (void *)&queue->fHIDQueue);
210        }
211    }
212}
213
214
215IOReturn IOHIDQueueClass::getAsyncPort(mach_port_t *port)
216{
217    IOReturn	ret = kIOReturnSuccess;
218
219    connectCheck();
220
221    if ( fAsyncPort == MACH_PORT_NULL ) {
222        ret = IOCreateReceivePort(kOSAsyncCompleteMessageID, &fAsyncPort);
223        if ( kIOReturnSuccess != ret )
224            return ret;
225
226        if ( fAsyncPort == MACH_PORT_NULL )
227            return kIOReturnNoMemory;
228
229        ret = setAsyncPort(fAsyncPort);
230    }
231
232    if (port)
233        *port = fAsyncPort;
234
235    return ret;
236}
237
238IOReturn IOHIDQueueClass::setAsyncPort(mach_port_t port)
239{
240    if ( !port )
241		return kIOReturnError;
242
243	fAsyncPort = port;
244
245	if (!fIsCreated)
246		return kIOReturnSuccess;
247
248	io_async_ref64_t		asyncRef;
249	uint64_t				input	= fQueueRef;
250	uint32_t				len		= 0;
251
252    return IOConnectCallAsyncScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientSetQueueAsyncPort, fAsyncPort, asyncRef, 1, &input, 1, 0, &len);
253}
254
255
256IOReturn IOHIDQueueClass::create (IOOptionBits flags, uint32_t depth)
257{
258    IOReturn ret = kIOReturnSuccess;
259
260    connectCheck();
261
262    // ���todo, check flags/depth to see if different (might need to recreate?)
263    if (fIsCreated)
264        dispose();
265
266    // sent message to create queue
267    uint64_t    input[2];
268    uint64_t    output;
269    uint32_t    outputCount = 1;
270
271    input[0] = flags;
272    input[1] = depth;
273
274    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientCreateQueue, input, 2, &output, &outputCount);
275
276    if (ret != kIOReturnSuccess)
277        return ret;
278
279    // we have created it
280    fIsCreated      = true;
281    fQueueRef       = output;
282    fCreatedFlags   = flags;
283    fCreatedDepth   = depth;
284
285    // if we have async port, set it on other side
286    if (fAsyncPort)
287    {
288        ret = setAsyncPort(fAsyncPort);
289        if (ret != kIOReturnSuccess) {
290            (void) this->dispose();
291            return ret;
292        }
293    }
294
295    if (!fElements)
296        fElements = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
297    else {
298        IOHIDElementRef *   elements;
299        CFIndex             i, count = CFSetGetCount(fElements);
300
301        elements = (IOHIDElementRef *)malloc(sizeof(IOHIDElementRef) *  count);
302
303        if (elements)
304        {
305            for (i=0; i<count; i++)
306                addElement(elements[i]);
307
308            free(elements);
309        }
310    }
311
312    return ret;
313}
314
315IOReturn IOHIDQueueClass::dispose()
316{
317    IOReturn ret = kIOReturnSuccess;
318
319    mostChecks();
320
321    // ���� TODO unmap memory when that call works
322    if ( fQueueMappedMemory )
323    {
324#if !__LP64__
325    vm_address_t        mappedMem = (vm_address_t)fQueueMappedMemory;
326#else
327    mach_vm_address_t   mappedMem = (mach_vm_address_t)fQueueMappedMemory;
328#endif
329
330        ret = IOConnectUnmapMemory (fOwningDevice->fConnection,
331                                    fQueueRef,
332                                    mach_task_self(),
333                                    mappedMem);
334        fQueueMappedMemory = NULL;
335        fQueueMappedMemorySize = 0;
336    }
337
338
339    uint64_t    input = fQueueRef;
340    uint32_t    outputCount = 0;
341
342    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientDisposeQueue, &input, 1, 0, &outputCount);
343
344    if (ret != kIOReturnSuccess)
345        return ret;
346
347    // mark it dead
348    fIsCreated = false;
349
350    fQueueRef = 0;
351
352    return kIOReturnSuccess;
353}
354
355IOReturn IOHIDQueueClass::getDepth(uint32_t * pDepth)
356{
357    *pDepth = fCreatedDepth;
358    return kIOReturnSuccess;
359}
360
361/* Any number of hid elements can feed the same queue */
362IOReturn IOHIDQueueClass::addElement (IOHIDElementRef element, IOOptionBits options)
363{
364    IOReturn    ret = kIOReturnSuccess;
365
366    if (!element)
367        return kIOReturnBadArgument;
368
369    mostChecks();
370
371    uint64_t    input[3];
372    uint64_t    sizeChange;
373    uint32_t    outputCount = 1;
374
375    input[0] = fQueueRef;
376    input[1] = (uint64_t)IOHIDElementGetCookie(element);
377    input[2] = options;
378
379    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientAddElementToQueue, input, 3, &sizeChange, &outputCount);
380
381    if (ret != kIOReturnSuccess)
382        return ret;
383
384    fQueueEntrySizeChanged = sizeChange;
385
386    if (fElements)
387        CFSetSetValue(fElements, element);
388
389    return kIOReturnSuccess;
390}
391
392IOReturn IOHIDQueueClass::removeElement (IOHIDElementRef element, IOOptionBits options __unused)
393{
394    IOReturn ret = kIOReturnSuccess;
395
396    if (!element)
397        return kIOReturnBadArgument;
398
399    mostChecks();
400
401    uint64_t    input[2];
402    uint64_t    sizeChange;
403    uint32_t    outputCount = 1;
404
405    input[0] = fQueueRef;
406    input[1] = (uint64_t)IOHIDElementGetCookie(element);
407
408    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientRemoveElementFromQueue, input, 2, &sizeChange, &outputCount);
409
410    if (ret != kIOReturnSuccess)
411        return ret;
412
413    fQueueEntrySizeChanged = sizeChange;
414
415    if (fElements)
416        CFSetRemoveValue(fElements, element);
417
418    return kIOReturnSuccess;
419}
420
421IOReturn IOHIDQueueClass::hasElement (IOHIDElementRef element, Boolean * pValue, IOOptionBits options __unused)
422{
423    if (!element || !pValue)
424        return kIOReturnBadArgument;
425
426    mostChecks();
427
428    uint64_t    input[2];
429    uint64_t    returnHasElement;
430    uint32_t    outputCount = 1;
431
432    input[0] = fQueueRef;
433    input[1] = (uint64_t)IOHIDElementGetCookie(element);
434
435    IOReturn ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientQueueHasElement, input, 2, &returnHasElement, &outputCount);
436
437    *pValue = returnHasElement;
438
439    return ret;
440}
441
442
443/* start/stop data delivery to a queue */
444IOReturn IOHIDQueueClass::start (IOOptionBits options __unused)
445{
446    IOReturn ret = kIOReturnSuccess;
447
448    mostChecks();
449
450    // if the queue size changes, we will need to dispose of the
451    // queue mapped memory
452    if ( fQueueEntrySizeChanged && fQueueMappedMemory )
453    {
454        ret = IOConnectUnmapMemory (fOwningDevice->fConnection,
455                                    fQueueRef,
456                                    mach_task_self(),
457                                    (uintptr_t)fQueueMappedMemory);
458        fQueueMappedMemory      = NULL;
459        fQueueMappedMemorySize  = 0;
460    }
461
462    uint64_t    input       = fQueueRef;
463    uint32_t    outputCount = 0;
464
465    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientStartQueue, &input, 1, 0, &outputCount);
466
467    if (ret != kIOReturnSuccess)
468        return ret;
469
470    // get the queue shared memory
471    if ( !fQueueMappedMemory )
472    {
473#if !__LP64__
474        vm_address_t        address = nil;
475        vm_size_t           size    = 0;
476#else
477        mach_vm_address_t   address = nil;
478        mach_vm_size_t      size    = 0;
479#endif
480
481        ret = IOConnectMapMemory (	fOwningDevice->fConnection,
482                                    fQueueRef,
483                                    mach_task_self(),
484                                    &address,
485                                    &size,
486                                    kIOMapAnywhere	);
487        if (ret == kIOReturnSuccess)
488        {
489            fQueueMappedMemory = (IODataQueueMemory *) address;
490            fQueueMappedMemorySize = size;
491            fQueueEntrySizeChanged  = false;
492        }
493    }
494
495    return kIOReturnSuccess;
496}
497
498IOReturn IOHIDQueueClass::stop (IOOptionBits options __unused)
499{
500    IOReturn ret = kIOReturnSuccess;
501
502    allChecks();
503
504    uint64_t    input       = fQueueRef;
505    uint32_t    outputCount = 0;
506
507    ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientStopQueue, &input, 1, 0, &outputCount);
508
509    if (ret != kIOReturnSuccess)
510        return ret;
511
512    // ��� TODO after we stop the queue, we should empty the queue here, in user space
513    // (to be consistant with setting the head from user space)
514
515    return kIOReturnSuccess;
516}
517
518IOReturn IOHIDQueueClass::copyNextEventValue (IOHIDValueRef     *pEvent,
519                                              uint32_t          timeout __unused,
520                                              IOOptionBits      options __unused)
521{
522    IOReturn ret = kIOReturnSuccess;
523
524    allChecks();
525
526    if ( !fQueueMappedMemory )
527        return kIOReturnNoMemory;
528
529    // check entry size
530    IODataQueueEntry *  nextEntry = IODataQueuePeek(fQueueMappedMemory);
531    uint32_t            entrySize;
532
533	// if queue empty, then stop
534	if (nextEntry == NULL)
535		return kIOReturnUnderrun;
536
537    entrySize = nextEntry->size;
538    ROSETTA_ONLY(
539        entrySize = OSSwapInt32(entrySize);
540    );
541
542    uint32_t dataSize = sizeof(IOHIDElementValue);
543
544    // check size of next entry
545    // Make sure that it is not smaller than IOHIDElementValue
546    if (entrySize < sizeof(IOHIDElementValue))
547        HIDLog ("IOHIDQueueClass: Queue size mismatch (%ld, %ld)\n", entrySize, sizeof(IOHIDElementValue));
548
549    // dequeue the item
550//    HIDLog ("IOHIDQueueClass::getNextEvent about to dequeue\n");
551    ret = IODataQueueDequeue(fQueueMappedMemory, NULL, &dataSize);
552//    HIDLog ("IODataQueueDequeue result %lx\n", (uint32_t) ret);
553
554
555    // if we got an entry
556    if (ret == kIOReturnSuccess && nextEntry)
557    {
558        IOHIDElementValue * nextElementValue = (IOHIDElementValue *) &(nextEntry->data);
559        IOHIDElementCookie  cookie = nextElementValue->cookie;
560
561        ROSETTA_ONLY(
562            cookie = (IOHIDElementCookie)OSSwapInt32((uint32_t)cookie);
563        );
564
565        if ( pEvent )
566            *pEvent = _IOHIDValueCreateWithElementValuePtr(kCFAllocatorDefault, fOwningDevice->getElement(cookie), nextElementValue);
567    }
568
569    return ret;
570}
571
572IOReturn IOHIDQueueClass::setEventCallback (IOHIDCallback callback, void * refcon)
573{
574    fEventCallback = callback;
575    fEventRefcon = refcon;
576
577    return kIOReturnSuccess;
578}
579
580IOHIDDeviceQueueInterface IOHIDQueueClass::sHIDQueueInterfaceV2 =
581{
582    0,
583    &IOHIDIUnknown::genericQueryInterface,
584    &IOHIDIUnknown::genericAddRef,
585    &IOHIDIUnknown::genericRelease,
586    &IOHIDQueueClass::_getAsyncEventSource,
587    &IOHIDQueueClass::_setDepth,
588    &IOHIDQueueClass::_getDepth,
589    &IOHIDQueueClass::_addElement,
590    &IOHIDQueueClass::_removeElement,
591    &IOHIDQueueClass::_hasElement,
592    &IOHIDQueueClass::_start,
593    &IOHIDQueueClass::_stop,
594    &IOHIDQueueClass::_setEventCallback,
595    &IOHIDQueueClass::_copyNextEventValue
596};
597
598IOReturn IOHIDQueueClass::_getAsyncEventSource(void *self, CFTypeRef *source)
599    { return getThis(self)->getAsyncEventSource(source); }
600
601IOReturn IOHIDQueueClass::_getAsyncPort(void *self, mach_port_t *port)
602    { return getThis(self)->getAsyncPort(port); }
603
604IOReturn IOHIDQueueClass::_setDepth(void *self, uint32_t depth, IOOptionBits options)
605    { return getThis(self)->create(options, depth); }
606
607IOReturn IOHIDQueueClass::_getDepth(void *self, uint32_t *pDepth)
608    { return getThis(self)->getDepth(pDepth); }
609
610IOReturn IOHIDQueueClass::_addElement (void * self, IOHIDElementRef element, IOOptionBits options)
611    { return getThis(self)->addElement(element, options); }
612
613IOReturn IOHIDQueueClass::_removeElement (void * self, IOHIDElementRef element, IOOptionBits options)
614    { return getThis(self)->removeElement(element, options); }
615
616IOReturn IOHIDQueueClass::_hasElement (void * self, IOHIDElementRef element, Boolean * pValue, IOOptionBits options)
617    { return getThis(self)->hasElement(element, pValue, options); }
618
619IOReturn IOHIDQueueClass::_start (void * self, IOOptionBits options)
620    { return getThis(self)->start(options); }
621
622IOReturn IOHIDQueueClass::_stop (void * self, IOOptionBits options)
623    { return getThis(self)->stop(options); }
624
625IOReturn IOHIDQueueClass::_copyNextEventValue (void * self, IOHIDValueRef * pEvent, uint32_t timeout, IOOptionBits options)
626    { return getThis(self)->copyNextEventValue(pEvent, timeout, options); }
627
628IOReturn IOHIDQueueClass::_setEventCallback (void * self, IOHIDCallback callback, void * refcon)
629    { return getThis(self)->setEventCallback(callback, refcon); }
630
631
632
633//****************************************************************************************************
634// Class:       IOHIDObsoleteQueueClass
635// Subclasses:  IOHIDQueueClass
636//****************************************************************************************************
637IOHIDQueueInterface IOHIDObsoleteQueueClass::sHIDQueueInterface =
638{
639    0,
640    &IOHIDIUnknown::genericQueryInterface,
641    &IOHIDIUnknown::genericAddRef,
642    &IOHIDIUnknown::genericRelease,
643    &IOHIDObsoleteQueueClass::_createAsyncEventSource,
644    &IOHIDObsoleteQueueClass::_getAsyncEventSource,
645    &IOHIDQueueClass::_getAsyncPort,
646    &IOHIDObsoleteQueueClass::_getAsyncPort,
647    &IOHIDObsoleteQueueClass::_create,
648    &IOHIDObsoleteQueueClass::_dispose,
649    &IOHIDObsoleteQueueClass::_addElement,
650    &IOHIDObsoleteQueueClass::_removeElement,
651    &IOHIDObsoleteQueueClass::_hasElement,
652    &IOHIDObsoleteQueueClass::_start,
653    &IOHIDObsoleteQueueClass::_stop,
654    &IOHIDObsoleteQueueClass::_getNextEvent,
655    &IOHIDObsoleteQueueClass::_setEventCallout,
656    &IOHIDObsoleteQueueClass::_getEventCallout,
657};
658
659// Methods for routing asynchronous completion plumbing.
660IOReturn IOHIDObsoleteQueueClass::_createAsyncEventSource(void * self, CFRunLoopSourceRef * pSource)
661{
662    return getThis(self)->createAsyncEventSource(pSource);
663}
664
665CFRunLoopSourceRef IOHIDObsoleteQueueClass::_getAsyncEventSource(void *self)
666{
667    CFTypeRef source = NULL;
668    getThis(self)->getAsyncEventSource(&source);
669    return (CFRunLoopSourceRef)source;
670}
671
672mach_port_t IOHIDObsoleteQueueClass::_getAsyncPort(void *self)
673    { mach_port_t port = MACH_PORT_NULL; getThis(self)->getAsyncPort(&port); return port; }
674
675IOReturn IOHIDObsoleteQueueClass::_create (void * self, uint32_t flags, uint32_t depth)
676    { return getThis(self)->create(flags, depth); }
677
678IOReturn IOHIDObsoleteQueueClass::_dispose (void * self)
679    { return getThis(self)->dispose(); }
680
681IOReturn IOHIDObsoleteQueueClass::_addElement (void * self, IOHIDElementCookie cookie, uint32_t flags)
682    { return getThis(self)->addElement(cookie, flags); }
683
684IOReturn IOHIDObsoleteQueueClass::_removeElement (void * self, IOHIDElementCookie elementCookie)
685    { return getThis(self)->removeElement(elementCookie); }
686
687Boolean IOHIDObsoleteQueueClass::_hasElement (void * self, IOHIDElementCookie elementCookie)
688    { return getThis(self)->hasElement(elementCookie); }
689
690IOReturn IOHIDObsoleteQueueClass::_start (void * self)
691    { return getThis(self)->start(); }
692
693IOReturn IOHIDObsoleteQueueClass::_stop (void * self)
694    { return getThis(self)->stop(); }
695
696IOReturn IOHIDObsoleteQueueClass::_getNextEvent (void * self, IOHIDEventStruct * event, AbsoluteTime maxTime, uint32_t timeoutMS)
697    { return getThis(self)->getNextEvent(event, maxTime, timeoutMS); }
698
699IOReturn IOHIDObsoleteQueueClass::_setEventCallout (void * self, IOHIDCallbackFunction callback, void * target, void * refcon)
700    { return getThis(self)->setEventCallout (callback, target, refcon); }
701
702IOReturn IOHIDObsoleteQueueClass::_getEventCallout (void * self, IOHIDCallbackFunction * pCallback, void ** pTarget, void ** pRefcon)
703    { return getThis(self)->getEventCallout(pCallback, pTarget, pRefcon); }
704
705IOHIDObsoleteQueueClass::IOHIDObsoleteQueueClass() : IOHIDQueueClass()
706{
707    fHIDQueue.pseudoVTable = (IUnknownVTbl *)  &sHIDQueueInterface;
708    fHIDQueue.obj = this;
709
710    fCallback   = NULL;
711    fTarget     = NULL;
712    fRefcon     = NULL;
713}
714
715HRESULT IOHIDObsoleteQueueClass::queryInterface(REFIID iid, void **	ppv)
716{
717    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
718    HRESULT res = S_OK;
719
720    if (CFEqual(uuid, kIOHIDQueueInterfaceID))
721    {
722        *ppv = getInterfaceMap();
723        addRef();
724    }
725    else {
726        res = fOwningDevice->queryInterface(iid, ppv);
727    }
728
729    if (!*ppv)
730        res = E_NOINTERFACE;
731
732    CFRelease(uuid);
733    return res;
734}
735
736IOReturn IOHIDObsoleteQueueClass::createAsyncEventSource(CFRunLoopSourceRef * pSource)
737{
738    IOReturn ret = IOHIDQueueClass::getAsyncEventSource((CFTypeRef *)pSource);
739
740    if ( ret == kIOReturnSuccess && pSource && *pSource )
741        CFRetain(*pSource);
742
743    return ret;
744}
745
746
747IOReturn IOHIDObsoleteQueueClass::addElement (IOHIDElementCookie cookie, uint32_t flags)
748{
749    return IOHIDQueueClass::addElement(fOwningDevice->getElement(cookie), flags);
750}
751
752IOReturn
753IOHIDObsoleteQueueClass::addElement (IOHIDElementRef element,
754                                     IOOptionBits options)
755{
756    return IOHIDQueueClass::addElement(element, options);
757}
758
759
760IOReturn IOHIDObsoleteQueueClass::removeElement (IOHIDElementCookie cookie)
761{
762    return IOHIDQueueClass::removeElement(fOwningDevice->getElement(cookie));
763}
764
765IOReturn
766IOHIDObsoleteQueueClass::removeElement (IOHIDElementRef element,
767                                        IOOptionBits options)
768{
769    return IOHIDQueueClass::removeElement(element, options);
770}
771
772
773Boolean IOHIDObsoleteQueueClass::hasElement (IOHIDElementCookie cookie)
774{
775    IOHIDElementRef element = fOwningDevice->getElement(cookie);
776    Boolean         value   = FALSE;
777
778    return (IOHIDQueueClass::hasElement(element, &value) == kIOReturnSuccess) ? value : FALSE;
779}
780
781IOReturn
782IOHIDObsoleteQueueClass::hasElement (IOHIDElementRef element,
783                                Boolean * pValue,
784                                IOOptionBits options)
785{
786    return IOHIDQueueClass::hasElement(element, pValue, options);
787}
788
789IOReturn IOHIDObsoleteQueueClass::getNextEvent (IOHIDEventStruct * pEventStruct, AbsoluteTime maxTime __unused, uint32_t timeoutMS)
790{
791    IOHIDValueRef   event = NULL;
792    IOReturn        ret   = kIOReturnBadArgument;
793
794    if (pEventStruct)
795    {
796        ret = copyNextEventValue(&event, timeoutMS);
797
798        if ((ret==kIOReturnSuccess) && event)
799        {
800            uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event));
801
802            pEventStruct->type                  = IOHIDElementGetType(IOHIDValueGetElement(event));
803            pEventStruct->elementCookie         = IOHIDElementGetCookie(IOHIDValueGetElement(event));
804            *(UInt64 *)&pEventStruct->timestamp = IOHIDValueGetTimeStamp(event);
805
806            if ( length > sizeof(uint32_t) )
807            {
808                pEventStruct->longValueSize = length;
809                pEventStruct->longValue     = malloc(length);
810                bcopy(IOHIDValueGetBytePtr(event), pEventStruct->longValue, length);
811            }
812            else
813            {
814                pEventStruct->longValueSize = 0;
815                pEventStruct->longValue     = NULL;
816                pEventStruct->value         = IOHIDValueGetIntegerValue(event);
817            }
818
819            CFRelease(event);
820        }
821    }
822
823    return ret;
824}
825
826IOReturn IOHIDObsoleteQueueClass::getEventCallout (IOHIDCallbackFunction * pCallback, void ** pTarget, void ** pRefcon)
827{
828    if (pCallback)  *pCallback  = fCallback;
829    if (pTarget)    *pTarget    = fTarget;
830    if (pRefcon)    *pRefcon    = fRefcon;
831
832    return kIOReturnSuccess;
833}
834
835IOReturn IOHIDObsoleteQueueClass::setEventCallout (IOHIDCallbackFunction callback, void * target, void * refcon)
836{
837    fCallback   = callback;
838    fTarget     = target;
839    fRefcon     = refcon;
840
841    IOHIDQueueClass::setEventCallback(IOHIDObsoleteQueueClass::_eventCallback, this);
842
843    return kIOReturnSuccess;
844}
845
846void IOHIDObsoleteQueueClass::_eventCallback(void * refcon, IOReturn result, void * sender)
847{
848    IOHIDObsoleteQueueClass * self = (IOHIDObsoleteQueueClass *) refcon;
849
850    if ( self->fCallback )
851        (*self->fCallback)(self->fTarget, result, self->fRefcon, sender);
852}
853
854