1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#define CFRUNLOOP_NEW_API 1
26
27#include <CoreFoundation/CFMachPort.h>
28//#include <IOKit/hid/IOHIDLib.h>
29//#include <unistd.h>
30
31#include "IOHIDTransactionClass.h"
32#include "IOHIDLibUserClient.h"
33#include "IOHIDTransactionElement.h"
34
35__BEGIN_DECLS
36#include <mach/mach_interface.h>
37#include <mach/mach.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 seizeCheck() do {               \
65    if ((!fOwningDevice) ||             \
66         (!fOwningDevice->isValid()))    \
67        return kIOReturnExclusiveAccess;\
68} while (0)
69
70
71#define mostChecks() do {   \
72    connectCheck();		    \
73    createdCheck();         \
74} while (0)
75
76#define allChecks() do {    \
77    mostChecks();           \
78    openCheck();		    \
79    seizeCheck();           \
80} while (0)
81
82IOHIDTransactionClass::IOHIDTransactionClass() : IOHIDIUnknown(NULL)
83{
84    fHIDTransaction.pseudoVTable    = (IUnknownVTbl *)  &sHIDTransactionInterface;
85    fHIDTransaction.obj             = this;
86
87    fDirection                      = 0;
88    fIsCreated                      = false;
89    fOwningDevice                   = NULL;
90    fEventCallback                  = NULL;
91    fEventRefcon                    = NULL;
92    fElementDictionaryRef           = NULL;
93}
94
95IOHIDTransactionClass::~IOHIDTransactionClass()
96{
97    if (fIsCreated)
98        dispose();
99
100    if( fOwningDevice )
101        fOwningDevice->detachTransaction(this);
102
103}
104
105HRESULT IOHIDTransactionClass::queryInterface(REFIID iid, void ** ppv)
106{
107    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
108    HRESULT res = S_OK;
109
110    if (CFEqual(uuid, kIOHIDDeviceTransactionInterfaceID))
111    {
112        *ppv = getInterfaceMap();
113        addRef();
114    }
115    else {
116        res = fOwningDevice->queryInterface(iid, ppv);
117    }
118
119    if (!*ppv)
120        res = E_NOINTERFACE;
121
122    CFRelease(uuid);
123    return res;
124}
125
126IOReturn IOHIDTransactionClass::getAsyncEventSource(CFTypeRef *source)
127{
128    connectCheck();
129
130    return fOwningDevice->getAsyncEventSource(source);
131}
132
133void IOHIDTransactionClass::_eventSourceCallback(CFMachPortRef *cfPort __unused, mach_msg_header_t *msg __unused, CFIndex size __unused, void *info)
134{
135
136    IOHIDTransactionClass *transaction = (IOHIDTransactionClass *)info;
137
138    if ( transaction && transaction->fEventCallback)
139    {
140        (transaction->fEventCallback)(transaction->fEventRefcon, kIOReturnSuccess, (void *)&transaction->fHIDTransaction);
141    }
142}
143
144IOReturn IOHIDTransactionClass::getAsyncPort(mach_port_t *port)
145{
146    connectCheck();
147
148    return fOwningDevice->getAsyncPort(port);
149}
150
151IOReturn IOHIDTransactionClass::getDirection(IOHIDTransactionDirectionType * pDirection)
152{
153    if (!pDirection)
154        return kIOReturnBadArgument;
155
156    *pDirection = fDirection;
157
158    return kIOReturnSuccess;
159}
160
161IOReturn IOHIDTransactionClass::setDirection(IOHIDTransactionDirectionType direction, IOOptionBits options __unused)
162{
163    IOHIDTransactionElementRef *elementRefs = NULL;
164    IOHIDElementRef             element = NULL;
165    CFStringRef                *keyRefs= NULL;
166    CFIndex                     numElements	= 0;
167
168    if (!fIsCreated || !fElementDictionaryRef)
169        return kIOReturnError;
170
171    // RY: If we change directions, we should remove the opposite direction elements
172    // from the transaction.  I might decide to leave them alone in the future and
173    // just ignore them during the commit.
174    numElements = CFDictionaryGetCount(fElementDictionaryRef);
175
176    if (!numElements)
177        return kIOReturnError;
178
179    elementRefs = (IOHIDTransactionElementRef *)malloc(sizeof(IOHIDTransactionElementRef) * numElements);
180    keyRefs     = (CFStringRef *)malloc(sizeof(CFStringRef) * numElements);
181    CFDictionaryGetKeysAndValues(fElementDictionaryRef, (const void **)keyRefs, (const void **)elementRefs);
182
183    for (int i=0;i<numElements && elementRefs[i] && keyRefs[i]; i++)
184    {
185        element = IOHIDTransactionElementGetElement(elementRefs[i]);
186        if (((IOHIDElementGetType(element) == kIOHIDElementTypeOutput) && (direction == kIOHIDTransactionDirectionTypeInput)) ||
187            ((IOHIDElementGetType(element) >= kIOHIDElementTypeInput_Misc) && (IOHIDElementGetType(element) <= kIOHIDElementTypeInput_ScanCodes) && (direction == kIOHIDTransactionDirectionTypeOutput)))
188            CFDictionaryRemoveValue(fElementDictionaryRef, keyRefs[i]);
189    }
190
191    if (elementRefs)
192        free(elementRefs);
193
194    if (keyRefs)
195        free(keyRefs);
196
197    fDirection = direction;
198
199    return kIOReturnSuccess;
200}
201
202IOReturn IOHIDTransactionClass::create ()
203{
204    IOReturn ret = kIOReturnSuccess;
205
206    connectCheck();
207
208    if (fIsCreated)
209        return kIOReturnSuccess;
210
211    // Create the mutable dictionary that will hold the transaction elements.
212    fElementDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
213
214    if (!fElementDictionaryRef)
215        return kIOReturnNoMemory;
216
217    // we have created it
218    fIsCreated = true;
219
220    return ret;
221}
222
223IOReturn IOHIDTransactionClass::dispose()
224{
225    IOReturn ret = kIOReturnSuccess;
226
227    // mark it dead
228    fIsCreated = false;
229
230    if (fElementDictionaryRef)
231    {
232        CFRelease(fElementDictionaryRef);
233        fElementDictionaryRef = NULL;
234    }
235
236    return ret;
237}
238
239IOReturn IOHIDTransactionClass::addElement (IOHIDElementRef element, IOOptionBits options __unused)
240{
241    IOHIDTransactionElementRef  transactionElement;
242    IOHIDElementType            elementType;
243    IOReturn                    ret = kIOReturnSuccess;
244    Boolean                     added = false;
245
246    mostChecks();
247
248    if (!element)
249        return kIOReturnBadArgument;
250
251    if (!fIsCreated || hasElement(element, &added) || added)
252        return kIOReturnError;
253
254    elementType = IOHIDElementGetType(element);
255
256    // Since this is a Output Transaction only allow feature and output elements
257    if ((elementType != kIOHIDElementTypeOutput) && (elementType != kIOHIDElementTypeFeature))
258        return kIOReturnBadArgument;
259
260    transactionElement = IOHIDTransactionElementCreate(kCFAllocatorDefault, element, 0);
261
262    if (!fElementDictionaryRef || !transactionElement)
263        ret = kIOReturnError;
264    else
265        CFDictionarySetValue(fElementDictionaryRef, element, transactionElement);
266
267    if (transactionElement) CFRelease(transactionElement);
268
269    return kIOReturnSuccess;
270}
271
272IOReturn IOHIDTransactionClass::removeElement (IOHIDElementRef element, IOOptionBits options __unused)
273{
274    Boolean added;
275
276    mostChecks();
277
278    if (!element)
279        return kIOReturnBadArgument;
280
281    if (!fIsCreated || !fElementDictionaryRef || hasElement(element, &added) || !added)
282        return kIOReturnError;
283
284    CFDictionaryRemoveValue(fElementDictionaryRef, element);
285
286    return kIOReturnSuccess;
287}
288
289IOReturn IOHIDTransactionClass::hasElement (IOHIDElementRef element, Boolean *pValue, IOOptionBits options __unused)
290{
291    mostChecks();
292
293    if (!element || !pValue)
294        return kIOReturnBadArgument;
295
296    if (!fIsCreated || !fElementDictionaryRef)
297        return kIOReturnError;
298
299    *pValue = CFDictionaryContainsKey(fElementDictionaryRef, element);
300
301    return kIOReturnSuccess;
302}
303
304IOReturn IOHIDTransactionClass::setElementValue(IOHIDElementRef element, IOHIDValueRef event, IOOptionBits options)
305{
306    IOHIDTransactionElementRef transactionElement;
307
308    mostChecks();
309
310    if (!element || (fDirection == kIOHIDTransactionDirectionTypeInput))
311        return kIOReturnBadArgument;
312
313    if (!fIsCreated || !fElementDictionaryRef)
314        return kIOReturnError;
315
316    transactionElement = (IOHIDTransactionElementRef)CFDictionaryGetValue(fElementDictionaryRef, element);
317
318    if (!transactionElement)
319        return kIOReturnError;
320
321    if ( options & kIOHIDTransactionOptionDefaultOutputValue )
322        IOHIDTransactionElementSetDefaultValue(transactionElement, event);
323    else
324        IOHIDTransactionElementSetValue(transactionElement, event);
325
326    return kIOReturnSuccess;
327}
328
329/* get the value for that element */
330IOReturn IOHIDTransactionClass::getElementValue(IOHIDElementRef element, IOHIDValueRef * pEvent, IOOptionBits options)
331{
332    IOHIDTransactionElementRef transactionElement;
333
334    mostChecks();
335
336    if (!element)
337        return kIOReturnBadArgument;
338
339    if (!fIsCreated || !fElementDictionaryRef)
340        return kIOReturnError;
341
342    transactionElement = (IOHIDTransactionElementRef)CFDictionaryGetValue(fElementDictionaryRef, element);
343
344    if (!transactionElement)
345        return kIOReturnError;
346
347    *pEvent = ((fDirection == kIOHIDTransactionDirectionTypeOutput) && (options & kIOHIDTransactionOptionDefaultOutputValue)) ?
348            IOHIDTransactionElementGetDefaultValue(transactionElement) : IOHIDTransactionElementGetValue(transactionElement);
349
350    return kIOReturnSuccess;
351}
352
353/* start/stop data delivery to a queue */
354IOReturn IOHIDTransactionClass::commit(uint32_t timeoutMS __unused, IOHIDCallback callback __unused, void * callbackRefcon __unused, IOOptionBits options __unused)
355{
356    IOHIDTransactionElementRef *    elementRefs         = NULL;
357    uint64_t *                      cookies             = NULL;
358    CFIndex                         numElements         = 0;
359    IOReturn                        ret                 = kIOReturnError;
360    int                             numValidElements = 0;
361    IOHIDValueRef                   event;
362
363    allChecks();
364
365    if (!fIsCreated || !fElementDictionaryRef)
366        return kIOReturnError;
367
368    numElements = CFDictionaryGetCount(fElementDictionaryRef);
369
370    if (!numElements)
371        return kIOReturnError;
372
373    cookies     = (uint64_t *)malloc(sizeof(uint64_t) * numElements);
374    elementRefs = (IOHIDTransactionElementRef *)malloc(sizeof(IOHIDTransactionElementRef) * numElements);
375
376    CFDictionaryGetKeysAndValues(fElementDictionaryRef, NULL, (const void **)elementRefs);
377
378    // run through and call setElementValue w/o device push
379    // *** we definitely have to hold a lock here. ***
380    for (int i=0;i<numElements && elementRefs[i]; i++)
381    {
382        if ( fDirection == kIOHIDTransactionDirectionTypeOutput )
383        {
384            if ((event = IOHIDTransactionElementGetValue(elementRefs[i])))
385            {
386                fOwningDevice->setElementValue(IOHIDTransactionElementGetElement(elementRefs[i]), event, 0, NULL, NULL, kHIDSetElementValuePendEvent);
387            }
388            else if ((event = IOHIDTransactionElementGetDefaultValue(elementRefs[i])))
389            {
390                fOwningDevice->setElementValue(IOHIDTransactionElementGetElement(elementRefs[i]), event, 0, NULL, NULL, kHIDSetElementValuePendEvent);
391            }
392            else
393                continue;
394        }
395
396        IOHIDTransactionElementSetValue(elementRefs[i], NULL);
397
398        cookies[numValidElements] = (uint32_t)IOHIDElementGetCookie(IOHIDTransactionElementGetElement(elementRefs[i]));
399        ROSETTA_ONLY(
400            cookies[numValidElements] = OSSwapInt32(cookies[numValidElements]);
401        );
402
403        numValidElements++;
404    }
405
406    uint32_t outputCount = 0;
407
408    if ( fDirection == kIOHIDTransactionDirectionTypeOutput )
409    {
410        ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientPostElementValues, cookies, numValidElements, 0, &outputCount);
411    }
412    else
413    {
414        // put together an ioconnect here
415        ret = IOConnectCallScalarMethod(fOwningDevice->fConnection, kIOHIDLibUserClientUpdateElementValues, cookies, numValidElements, 0, &outputCount);
416
417        for (int i=0;i<numElements && elementRefs[i]; i++)
418        {
419            fOwningDevice->getElementValue(IOHIDTransactionElementGetElement(elementRefs[i]), &event, 0, NULL, NULL, kHIDGetElementValuePreventPoll);
420            IOHIDTransactionElementSetValue(elementRefs[i], event);
421        }
422    }
423
424    if (elementRefs)
425        free(elementRefs);
426
427    if ( cookies )
428        free(cookies);
429
430    return ret;
431
432}
433
434IOReturn IOHIDTransactionClass::clear (IOOptionBits options __unused)
435{
436    IOHIDTransactionElementRef *elementRefs = NULL;
437    CFIndex                     numElements	= 0;
438
439    mostChecks();
440
441    if (!fIsCreated || !fElementDictionaryRef)
442        return kIOReturnError;
443
444    numElements = CFDictionaryGetCount(fElementDictionaryRef);
445
446    if (!numElements)
447        return kIOReturnError;
448
449    elementRefs = (IOHIDTransactionElementRef *)malloc(sizeof(IOHIDTransactionElementRef) * numElements);
450
451    CFDictionaryGetKeysAndValues(fElementDictionaryRef, NULL, (const void **)elementRefs);
452
453    for (int i=0;i<numElements && elementRefs[i]; i++)
454        IOHIDTransactionElementSetValue(elementRefs[i], NULL);
455
456    if (elementRefs)
457        free(elementRefs);
458
459    return kIOReturnSuccess;
460}
461
462IOHIDDeviceTransactionInterface IOHIDTransactionClass::sHIDTransactionInterface =
463{
464    0,
465    &IOHIDIUnknown::genericQueryInterface,
466    &IOHIDIUnknown::genericAddRef,
467    &IOHIDIUnknown::genericRelease,
468    &IOHIDTransactionClass::_getAsyncEventSource,
469    &IOHIDTransactionClass::_setDirection,
470    &IOHIDTransactionClass::_getDirection,
471    &IOHIDTransactionClass::_addElement,
472    &IOHIDTransactionClass::_removeElement,
473    &IOHIDTransactionClass::_hasElement,
474    &IOHIDTransactionClass::_setElementValue,
475    &IOHIDTransactionClass::_getElementValue,
476    &IOHIDTransactionClass::_commit,
477    &IOHIDTransactionClass::_clear,
478};
479
480IOReturn IOHIDTransactionClass::_getAsyncEventSource(void *self, CFTypeRef *source)
481    { return getThis(self)->getAsyncEventSource(source); }
482
483IOReturn IOHIDTransactionClass::_getAsyncPort(void *self, mach_port_t *port)
484    { return getThis(self)->getAsyncPort(port); }
485
486IOReturn IOHIDTransactionClass::_setDirection(void *self, IOHIDTransactionDirectionType direction, IOOptionBits options)
487    { return getThis(self)->setDirection(direction, options); }
488
489IOReturn IOHIDTransactionClass::_getDirection(void *self, IOHIDTransactionDirectionType * pDirection)
490    { return getThis(self)->getDirection(pDirection); }
491
492IOReturn IOHIDTransactionClass::_addElement (void * self, IOHIDElementRef element, IOOptionBits options)
493    { return getThis(self)->addElement(element, options); }
494
495IOReturn IOHIDTransactionClass::_removeElement (void * self, IOHIDElementRef element, IOOptionBits options)
496    { return getThis(self)->removeElement(element, options); }
497
498IOReturn IOHIDTransactionClass::_hasElement (void * self, IOHIDElementRef element, Boolean *pValue, IOOptionBits options)
499    { return getThis(self)->hasElement(element, pValue, options); }
500
501IOReturn IOHIDTransactionClass::_setElementValue(void * self, IOHIDElementRef element, IOHIDValueRef event, IOOptionBits options)
502    { return getThis(self)->setElementValue(element, event, options); }
503
504IOReturn IOHIDTransactionClass::_getElementValue(void * self, IOHIDElementRef element, IOHIDValueRef * pEvent, IOOptionBits options)
505    { return getThis(self)->getElementValue(element, pEvent, options); }
506
507IOReturn IOHIDTransactionClass::_commit(void * self, uint32_t timeoutMS, IOHIDCallback callback, void * callbackRefcon, IOOptionBits options)
508    { return getThis(self)->commit(timeoutMS, callback, callbackRefcon, options);}
509
510IOReturn IOHIDTransactionClass::_clear(void * self, IOOptionBits options)
511    { return getThis(self)->clear(options);}
512
513
514//****************************************************************************************************
515// Class:       IOHIDOutputTransactionClass
516// Subclasses:  IOHIDTransactionClass
517//****************************************************************************************************
518
519IOHIDOutputTransactionInterface IOHIDOutputTransactionClass::sHIDOutputTransactionInterface =
520{
521    0,
522    &IOHIDIUnknown::genericQueryInterface,
523    &IOHIDIUnknown::genericAddRef,
524    &IOHIDIUnknown::genericRelease,
525    &IOHIDOutputTransactionClass::_createAsyncEventSource,
526    &IOHIDOutputTransactionClass::_getAsyncEventSource,
527    &IOHIDTransactionClass::_getAsyncPort,
528    &IOHIDOutputTransactionClass::_getAsyncPort,
529    &IOHIDOutputTransactionClass::_create,
530    &IOHIDOutputTransactionClass::_dispose,
531    &IOHIDOutputTransactionClass::_addElement,
532    &IOHIDOutputTransactionClass::_removeElement,
533    &IOHIDOutputTransactionClass::_hasElement,
534    &IOHIDOutputTransactionClass::_setElementDefault,
535    &IOHIDOutputTransactionClass::_getElementDefault,
536    &IOHIDOutputTransactionClass::_setElementValue,
537    &IOHIDOutputTransactionClass::_getElementValue,
538    &IOHIDOutputTransactionClass::_commit,
539    &IOHIDOutputTransactionClass::_clear,
540};
541
542IOReturn IOHIDOutputTransactionClass::_createAsyncEventSource(void * self, CFRunLoopSourceRef * pSource)
543    { return getThis(self)->createAsyncEventSource(pSource); }
544
545CFRunLoopSourceRef IOHIDOutputTransactionClass::_getAsyncEventSource(void *self)
546    { CFTypeRef source = NULL; getThis(self)->getAsyncEventSource(&source); return (CFRunLoopSourceRef)source;}
547
548mach_port_t IOHIDOutputTransactionClass::_getAsyncPort(void *self)
549    { mach_port_t port = MACH_PORT_NULL; getThis(self)->getAsyncPort(&port); return port; }
550
551IOReturn IOHIDOutputTransactionClass::_create(void * self)
552    { return getThis(self)->create(); }
553
554IOReturn IOHIDOutputTransactionClass::_dispose (void * self)
555    { return getThis(self)->dispose(); }
556
557IOReturn IOHIDOutputTransactionClass::_addElement (void * self, IOHIDElementCookie cookie)
558    { return getThis(self)->addElement(cookie); }
559
560IOReturn IOHIDOutputTransactionClass::_removeElement (void * self, IOHIDElementCookie cookie)
561    { return getThis(self)->removeElement(cookie); }
562
563Boolean IOHIDOutputTransactionClass::_hasElement (void * self, IOHIDElementCookie cookie)
564    { return getThis(self)->hasElement(cookie); }
565
566IOReturn IOHIDOutputTransactionClass::_setElementDefault(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent)
567    { return getThis(self)->setElementValue(cookie, pEvent, kIOHIDTransactionOptionDefaultOutputValue); }
568
569IOReturn IOHIDOutputTransactionClass::_getElementDefault(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent)
570    { return getThis(self)->getElementValue(cookie, pEvent, kIOHIDTransactionOptionDefaultOutputValue); }
571
572IOReturn IOHIDOutputTransactionClass::_setElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent)
573    { return getThis(self)->setElementValue(cookie, pEvent); }
574
575IOReturn IOHIDOutputTransactionClass::_getElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent)
576    { return getThis(self)->getElementValue(cookie, pEvent); }
577
578IOReturn IOHIDOutputTransactionClass::_commit(void * self, uint32_t timeoutMS, IOHIDCallbackFunction callback, void * callbackTarget, void * callbackRefcon)
579    { return getThis(self)->commit(timeoutMS, callback, callbackTarget, callbackRefcon);}
580
581IOReturn IOHIDOutputTransactionClass::_clear(void * self)
582    { return getThis(self)->clear();}
583
584IOHIDOutputTransactionClass::IOHIDOutputTransactionClass() : IOHIDTransactionClass()
585{
586    fHIDTransaction.pseudoVTable = (IUnknownVTbl *)  &sHIDOutputTransactionInterface;
587    fHIDTransaction.obj = this;
588
589    fCallback   = NULL;
590    fTarget     = NULL;
591    fRefcon     = NULL;
592}
593
594IOHIDOutputTransactionClass::~IOHIDOutputTransactionClass()
595{
596}
597
598HRESULT IOHIDOutputTransactionClass::queryInterface(REFIID iid, void ** ppv)
599{
600    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
601    HRESULT res = S_OK;
602
603    if (CFEqual(uuid, kIOHIDOutputTransactionInterfaceID))
604    {
605        *ppv = getInterfaceMap();
606        addRef();
607    }
608    else {
609        res = fOwningDevice->queryInterface(iid, ppv);
610    }
611
612    if (!*ppv)
613        res = E_NOINTERFACE;
614
615    CFRelease(uuid);
616    return res;
617}
618
619IOReturn IOHIDOutputTransactionClass::createAsyncEventSource(CFRunLoopSourceRef * pSource)
620{
621    IOReturn ret = IOHIDTransactionClass::getAsyncEventSource((CFTypeRef *)pSource);
622
623    if ( ret == kIOReturnSuccess && pSource && *pSource )
624        CFRetain(*pSource);
625
626    return ret;
627}
628
629IOReturn IOHIDOutputTransactionClass::create ()
630{
631	fDirection = kIOHIDTransactionDirectionTypeOutput;
632
633    return IOHIDTransactionClass::create();
634}
635
636IOReturn IOHIDOutputTransactionClass::addElement (IOHIDElementCookie cookie)
637{
638    IOHIDElementRef element = fOwningDevice->getElement(cookie);
639
640    return IOHIDTransactionClass::addElement(element);
641}
642
643IOReturn
644IOHIDOutputTransactionClass::addElement(IOHIDElementRef element,
645                                        IOOptionBits options)
646{
647    return IOHIDTransactionClass::addElement(element, options);
648}
649
650IOReturn IOHIDOutputTransactionClass::removeElement (IOHIDElementCookie cookie)
651{
652    IOHIDElementRef element = fOwningDevice->getElement(cookie);
653
654    return IOHIDTransactionClass::removeElement(element);
655}
656
657IOReturn
658IOHIDOutputTransactionClass::removeElement(IOHIDElementRef element,
659                                           IOOptionBits options)
660{
661    return IOHIDTransactionClass::removeElement(element, options);
662}
663
664Boolean IOHIDOutputTransactionClass::hasElement (IOHIDElementCookie cookie)
665{
666    IOHIDElementRef element = fOwningDevice->getElement(cookie);
667    Boolean         value   = FALSE;
668
669    return (IOHIDTransactionClass::hasElement(element, &value) == kIOReturnSuccess) ? value : FALSE;
670}
671
672IOReturn
673IOHIDOutputTransactionClass::hasElement(IOHIDElementRef element,
674                                        Boolean * pValue,
675                                        IOOptionBits options)
676{
677    return IOHIDTransactionClass::hasElement(element, pValue, options);
678}
679
680/* set the value for that element */
681IOReturn
682IOHIDOutputTransactionClass::setElementValue(IOHIDElementCookie cookie,
683                                             IOHIDEventStruct * pEvent,
684                                             IOOptionBits options)
685{
686    IOHIDValueRef   event;
687    IOHIDElementRef element;
688    IOReturn        ret;
689
690    if ( !pEvent )
691        return kIOReturnBadArgument;
692
693    element =  fOwningDevice->getElement(cookie);
694    event   = _IOHIDValueCreateWithStruct(kCFAllocatorDefault, element, pEvent);
695
696    ret = IOHIDTransactionClass::setElementValue(element, event, options);
697
698    CFRelease(event);
699
700    return ret;
701}
702
703IOReturn
704IOHIDOutputTransactionClass::setElementValue(IOHIDElementRef element,
705                                             IOHIDValueRef event,
706                                             IOOptionBits options)
707{
708    return IOHIDTransactionClass::setElementValue(element, event, options);
709}
710
711/* get the value for that element */
712IOReturn
713IOHIDOutputTransactionClass::getElementValue(IOHIDElementCookie cookie,
714                                             IOHIDEventStruct * pEvent,
715                                             IOOptionBits options)
716{
717    IOHIDValueRef   event;
718    IOReturn        ret;
719
720    if ( !pEvent )
721        return kIOReturnBadArgument;
722
723    ret = IOHIDTransactionClass::getElementValue(fOwningDevice->getElement(cookie), &event, options);
724
725    if ((ret==kIOReturnSuccess) && event)
726    {
727        uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event));;
728
729        pEvent->type            = IOHIDElementGetType(IOHIDValueGetElement(event));
730        pEvent->elementCookie   = cookie;
731        *(UInt64 *)&pEvent->timestamp = IOHIDValueGetTimeStamp(event);
732
733        if ( length > sizeof(uint32_t) )
734        {
735            pEvent->longValueSize = length;
736            pEvent->longValue     = (void *)IOHIDValueGetBytePtr(event);
737        }
738        else
739        {
740            pEvent->longValueSize = 0;
741            pEvent->longValue     = NULL;
742            pEvent->value         = IOHIDValueGetIntegerValue(event);
743        }
744    }
745
746    return ret;
747}
748
749IOReturn
750IOHIDOutputTransactionClass::getElementValue(IOHIDElementRef element,
751                                             IOHIDValueRef * pEvent, IOOptionBits options)
752{
753    return IOHIDTransactionClass::getElementValue(element, pEvent, options);
754}
755
756IOReturn IOHIDOutputTransactionClass::commit(uint32_t timeoutMS, IOHIDCallbackFunction callback, void * target, void * refcon)
757{
758    fCallback   = callback;
759    fTarget     = target;
760    fRefcon     = refcon;
761
762    return IOHIDTransactionClass::commit(timeoutMS, IOHIDOutputTransactionClass::_commitCallback, this);
763}
764
765IOReturn
766IOHIDOutputTransactionClass::commit(uint32_t timeoutMS,
767                                    IOHIDCallback callback,
768                                    void * callbackRefcon,
769                                    IOOptionBits options)
770{
771    return IOHIDTransactionClass::commit(timeoutMS, callback, callbackRefcon, options);
772}
773
774void IOHIDOutputTransactionClass::_commitCallback(void * context, IOReturn result __unused, void * sender){
775
776    IOHIDOutputTransactionClass *transaction = (IOHIDOutputTransactionClass *)context;
777
778    if ( transaction && transaction->fCallback)
779    {
780        (transaction->fCallback)(transaction->fTarget, kIOReturnSuccess, transaction->fRefcon, sender);
781    }
782}
783