1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include "IOHIDEventServiceUserClient.h"
24#include "IOHIDEventServiceQueue.h"
25#include "IOHIDEventData.h"
26#include "IOHIDEvent.h"
27#include "IOHIDPrivateKeys.h"
28
29
30#define kQueueSizeMin   0
31#define kQueueSizeFake  128
32#define kQueueSizeMax   4096
33
34
35//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
36// __IOHIDEventServiceQueueFake
37//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
38class __IOHIDEventServiceQueueFake {
39public:
40    IOHIDEventServiceQueue * queue;
41
42    __IOHIDEventServiceQueueFake() {
43        queue = IOHIDEventServiceQueue::withCapacity(kQueueSizeFake);
44    };
45    ~__IOHIDEventServiceQueueFake() {
46        queue->release();
47    };
48};
49
50static __IOHIDEventServiceQueueFake __fakeQueue;
51
52
53//===========================================================================
54// IOHIDEventServiceUserClient class
55
56#define super IOUserClient
57
58OSDefineMetaClassAndStructors( IOHIDEventServiceUserClient, IOUserClient )
59
60//==============================================================================
61// IOHIDEventServiceUserClient::sMethods
62//==============================================================================
63const IOExternalMethodDispatch IOHIDEventServiceUserClient::sMethods[kIOHIDEventServiceUserClientNumCommands] = {
64    { //    kIOHIDEventServiceUserClientOpen
65	(IOExternalMethodAction) &IOHIDEventServiceUserClient::_open,
66	1, 0,
67    0, 0
68    },
69    { //    kIOHIDEventServiceUserClientClose
70	(IOExternalMethodAction) &IOHIDEventServiceUserClient::_close,
71	1, 0,
72    0, 0
73    },
74    { //    kIOHIDEventServiceUserClientCopyEvent
75	(IOExternalMethodAction) &IOHIDEventServiceUserClient::_copyEvent,
76	2, -1,
77    0, -1
78    },
79    { //    kIOHIDEventServiceUserClientSetElementValue
80	(IOExternalMethodAction) &IOHIDEventServiceUserClient::_setElementValue,
81	3, 0,
82    0, 0
83    },
84};
85
86
87//==============================================================================
88// IOHIDEventServiceUserClient::getService
89//==============================================================================
90IOService * IOHIDEventServiceUserClient::getService( void )
91{
92    return _owner;
93}
94
95//==============================================================================
96// IOHIDEventServiceUserClient::clientClose
97//==============================================================================
98IOReturn IOHIDEventServiceUserClient::clientClose( void )
99{
100   if (_client) {
101        task_deallocate(_client);
102        _client = 0;
103    }
104
105   if (_owner) {
106        _owner->close(this, _options);
107    }
108
109    terminate();
110
111    return kIOReturnSuccess;
112}
113
114//==============================================================================
115// IOHIDEventServiceUserClient::registerNotificationPort
116//==============================================================================
117IOReturn IOHIDEventServiceUserClient::registerNotificationPort(
118                            mach_port_t                 port,
119                            UInt32                      type,
120                            UInt32                      refCon )
121{
122    _queue->setNotificationPort(port);
123
124    return kIOReturnSuccess;
125}
126
127//==============================================================================
128// IOHIDEventServiceUserClient::clientMemoryForType
129//==============================================================================
130IOReturn IOHIDEventServiceUserClient::clientMemoryForType(
131                            UInt32                      type,
132                            IOOptionBits *              options,
133                            IOMemoryDescriptor **       memory )
134{
135    IOReturn ret = kIOReturnNoMemory;
136
137    if ( _queue ) {
138        IOMemoryDescriptor * memoryToShare = _queue->getMemoryDescriptor();
139
140        // if we got some memory
141        if (memoryToShare)
142        {
143            // Memory will be released by user client
144            // when last map is destroyed.
145
146            memoryToShare->retain();
147
148            ret = kIOReturnSuccess;
149        }
150
151        // set the result
152        *options = 0;
153        *memory  = memoryToShare;
154    }
155
156    return ret;
157}
158
159//==============================================================================
160// IOHIDEventServiceUserClient::externalMethod
161//==============================================================================
162typedef struct HIDCommandGateArgs {
163    uint32_t                    selector;
164    IOExternalMethodArguments * arguments;
165    IOExternalMethodDispatch *  dispatch;
166    OSObject *                  target;
167    void *                      reference;
168}HIDCommandGateArgs;
169
170IOReturn IOHIDEventServiceUserClient::externalMethod(
171                            uint32_t                    selector,
172                            IOExternalMethodArguments * arguments,
173                            IOExternalMethodDispatch *  dispatch,
174                            OSObject *                  target,
175                            void *                      reference)
176{
177    if (selector < (uint32_t) kIOHIDEventServiceUserClientNumCommands)
178    {
179        dispatch = (IOExternalMethodDispatch *) &sMethods[selector];
180
181        if (!target)
182            target = this;
183    }
184
185	return super::externalMethod(selector, arguments, dispatch, target, reference);
186}
187
188//==============================================================================
189// IOHIDEventServiceUserClient::initWithTask
190//==============================================================================
191bool IOHIDEventServiceUserClient::initWithTask(task_t owningTask, void * security_id, UInt32 type)
192{
193    if (!super::init())
194        return false;
195
196    _client = owningTask;
197
198    task_reference (_client);
199
200    return true;
201}
202
203//==============================================================================
204// IOHIDEventServiceUserClient::start
205//==============================================================================
206bool IOHIDEventServiceUserClient::start( IOService * provider )
207{
208    OSObject *  object;
209    uint32_t    queueSize = kQueueSizeMax;
210
211    if ( !super::start(provider) )
212        return false;
213
214    _owner = OSDynamicCast(IOHIDEventService, provider);
215    if ( !_owner )
216        return false;
217
218    object = provider->copyProperty(kIOHIDEventServiceQueueSize);
219    if ( OSDynamicCast(OSNumber, object) ) {
220        queueSize = ((OSNumber*)object)->unsigned32BitValue();
221        queueSize = min(kQueueSizeMax, queueSize);
222    }
223    OSSafeReleaseNULL(object);
224
225    if ( queueSize ) {
226        _queue = IOHIDEventServiceQueue::withCapacity(queueSize);
227    } else {
228        _queue = __fakeQueue.queue;
229        if ( _queue )
230            _queue->retain();
231    }
232
233    if ( !_queue )
234        return false;
235
236    return true;
237}
238
239//==============================================================================
240// IOHIDEventServiceUserClient::_open
241//==============================================================================
242IOReturn IOHIDEventServiceUserClient::_open(
243                                IOHIDEventServiceUserClient *   target,
244                                void *                          reference,
245                                IOExternalMethodArguments *     arguments)
246{
247    return target->open((IOOptionBits)arguments->scalarInput[0]);
248}
249
250//==============================================================================
251// IOHIDEventServiceUserClient::open
252//==============================================================================
253IOReturn IOHIDEventServiceUserClient::open(IOOptionBits options)
254{
255
256    // get ready just in case events start coming our way
257    _queue->setState(true);
258    _options = options;
259
260    if (!_owner->open(  this,
261                        options,
262                        NULL,
263                        OSMemberFunctionCast(IOHIDEventService::Action,
264                        this, &IOHIDEventServiceUserClient::eventServiceCallback)) ) {
265        _queue->setState(false);
266        return kIOReturnExclusiveAccess;
267    }
268
269    return kIOReturnSuccess;
270}
271
272//==============================================================================
273// IOHIDEventServiceUserClient::_close
274//==============================================================================
275IOReturn IOHIDEventServiceUserClient::_close(
276                                IOHIDEventServiceUserClient *   target,
277                                void *                          reference,
278                                IOExternalMethodArguments *     arguments)
279{
280    return target->close();
281}
282
283//==============================================================================
284// IOHIDEventServiceUserClient::close
285//==============================================================================
286IOReturn IOHIDEventServiceUserClient::close()
287{
288    _queue->setState(false);
289    _owner->close(this, _options);
290
291    return kIOReturnSuccess;
292}
293
294//==============================================================================
295// IOHIDEventServiceUserClient::_copyEvent
296//==============================================================================
297IOReturn IOHIDEventServiceUserClient::_copyEvent(
298                                IOHIDEventServiceUserClient *   target,
299                                void *                          reference,
300                                IOExternalMethodArguments *     arguments)
301{
302    IOHIDEvent *    inEvent     = NULL;
303    IOHIDEvent *    outEvent    = NULL;
304    IOReturn        ret         = kIOReturnError;
305    IOByteCount     length      = 0;
306
307    if ( arguments->structureInput && arguments->structureInputSize)
308        inEvent = IOHIDEvent::withBytes(arguments->structureInput, arguments->structureInputSize);
309
310    do {
311        outEvent = target->copyEvent(arguments->scalarInput[0], inEvent, arguments->scalarInput[1]);
312
313        if ( !outEvent )
314            break;
315
316        length = outEvent->getLength();
317
318        if ( length > arguments->structureOutputSize ) {
319            ret = kIOReturnBadArgument;
320            break;
321        }
322
323        outEvent->readBytes(arguments->structureOutput, length);
324        arguments->structureOutputSize = length;
325
326        ret = kIOReturnSuccess;
327
328    } while ( 0 );
329
330    if ( inEvent )
331        inEvent->release();
332
333    if ( outEvent )
334        outEvent->release();
335
336    return ret;
337}
338
339//==============================================================================
340// IOHIDEventServiceUserClient::copyEvent
341//==============================================================================
342IOHIDEvent * IOHIDEventServiceUserClient::copyEvent(IOHIDEventType type, IOHIDEvent * matching, IOOptionBits options)
343{
344    return _owner->copyEvent(type, matching, options);
345}
346
347//==============================================================================
348// IOHIDEventServiceUserClient::_setElementValue
349//==============================================================================
350IOReturn IOHIDEventServiceUserClient::_setElementValue(
351                                IOHIDEventServiceUserClient *   target,
352                                void *                          reference,
353                                IOExternalMethodArguments *     arguments)
354{
355    target->setElementValue(arguments->scalarInput[0], arguments->scalarInput[1], arguments->scalarInput[2]);
356
357    return kIOReturnSuccess;
358}
359
360//==============================================================================
361// IOHIDEventServiceUserClient::setElementValue
362//==============================================================================
363void IOHIDEventServiceUserClient::setElementValue(UInt32 usagePage, UInt32 usage, UInt32 value)
364{
365    return _owner->setElementValue(usagePage, usage, value);
366}
367
368//==============================================================================
369// IOHIDEventServiceUserClient::didTerminate
370//==============================================================================
371bool IOHIDEventServiceUserClient::didTerminate(IOService *provider, IOOptionBits options, bool *defer)
372{
373    _owner->close(this, _options);
374
375    return super::didTerminate(provider, options, defer);
376}
377
378//==============================================================================
379// IOHIDEventServiceUserClient::free
380//==============================================================================
381void IOHIDEventServiceUserClient::free()
382{
383    if (_queue) {
384        _queue->release();
385        _queue = 0;
386    }
387
388    if (_owner) {
389        _owner = 0;
390    }
391
392    super::free();
393}
394
395//==============================================================================
396// IOHIDEventServiceUserClient::setProperties
397//==============================================================================
398IOReturn IOHIDEventServiceUserClient::setProperties( OSObject * properties )
399{
400    return _owner->setProperties(properties);
401}
402
403//==============================================================================
404// IOHIDEventServiceUserClient::eventServiceCallback
405//==============================================================================
406void IOHIDEventServiceUserClient::eventServiceCallback(
407                                IOHIDEventService *             sender,
408                                void *                          context,
409                                IOHIDEvent *                    event,
410                                IOOptionBits                    options)
411{
412    if (!_queue || !_queue->getState() || _queue == __fakeQueue.queue )
413        return;
414
415    //enqueue the event
416    _queue->enqueueEvent(event);
417}
418