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
24#include <IOKit/system.h>
25#include <IOKit/IOLib.h>
26#include <IOKit/IODataQueueShared.h>
27#include "IOHIDEventQueue.h"
28
29enum {
30    kHIDQueueStarted    = 0x01,
31    kHIDQueueDisabled   = 0x02
32};
33
34#define super IOSharedDataQueue
35OSDefineMetaClassAndStructors( IOHIDEventQueue, super )
36
37//---------------------------------------------------------------------------
38// Factory methods.
39
40IOHIDEventQueue * IOHIDEventQueue::withCapacity( UInt32 size )
41{
42    IOHIDEventQueue * queue = new IOHIDEventQueue;
43
44    if ( queue && !queue->initWithCapacity(size) )
45    {
46        queue->release();
47        queue = 0;
48    }
49
50    queue->_state               = 0;
51    queue->_lock                = IOLockAlloc();
52    queue->_numEntries          = size / DEFAULT_HID_ENTRY_SIZE;
53    queue->_currentEntrySize    = DEFAULT_HID_ENTRY_SIZE;
54    queue->_maxEntrySize        = DEFAULT_HID_ENTRY_SIZE;
55
56    return queue;
57}
58
59IOHIDEventQueue * IOHIDEventQueue::withEntries( UInt32 numEntries,
60                                                UInt32 entrySize )
61{
62    IOHIDEventQueue * queue = new IOHIDEventQueue;
63
64    if ( queue && !queue->initWithEntries(numEntries, entrySize) )
65    {
66        queue->release();
67        queue = 0;
68    }
69
70    queue->_state               = 0;
71    queue->_lock                = IOLockAlloc();
72    queue->_numEntries          = numEntries;
73    queue->_currentEntrySize    = DEFAULT_HID_ENTRY_SIZE;
74    queue->_maxEntrySize        = DEFAULT_HID_ENTRY_SIZE;
75
76    return queue;
77}
78
79void IOHIDEventQueue::free()
80{
81    if (_lock)
82    {
83        IOLockLock(_lock);
84        IOLock*	 tempLock = _lock;
85        _lock = NULL;
86        IOLockUnlock(tempLock);
87        IOLockFree(tempLock);
88    }
89
90    if ( _descriptor )
91    {
92        _descriptor->release();
93        _descriptor = 0;
94    }
95
96    super::free();
97}
98
99
100//---------------------------------------------------------------------------
101// Add data to the queue.
102
103Boolean IOHIDEventQueue::enqueue( void * data, UInt32 dataSize )
104{
105    Boolean ret = true;
106
107    if ( _lock )
108        IOLockLock(_lock);
109
110    // if we are not started, then dont enqueue
111    // for now, return true, since we dont wish to push an error back
112    if ((_state & (kHIDQueueStarted | kHIDQueueDisabled)) == kHIDQueueStarted)
113        ret = super::enqueue(data, dataSize);
114
115    if ( _lock )
116        IOLockUnlock(_lock);
117
118    return ret;
119}
120
121
122//---------------------------------------------------------------------------
123// Start the queue.
124
125void IOHIDEventQueue::start()
126{
127    if ( _lock )
128        IOLockLock(_lock);
129
130    if ( _state & kHIDQueueStarted )
131        goto START_END;
132
133    if ( _currentEntrySize != _maxEntrySize )
134    {
135        mach_port_t port = notifyMsg ? ((mach_msg_header_t *)notifyMsg)->msgh_remote_port : MACH_PORT_NULL;
136
137        // Free the existing queue data
138        if (dataQueue) {
139            IOFreeAligned(dataQueue, round_page_32(getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE));
140        }
141
142        if (_descriptor) {
143            _descriptor->release();
144            _descriptor = 0;
145        }
146
147        // init the queue again.  This will allocate the appropriate data.
148        if ( !initWithEntries(_numEntries, _maxEntrySize) ) {
149            goto START_END;
150        }
151
152        _currentEntrySize = _maxEntrySize;
153
154        // RY: since we are initing the queue, we should reset the port as well
155        if ( port )
156            setNotificationPort(port);
157    }
158    else if ( dataQueue )
159    {
160        dataQueue->head = 0;
161        dataQueue->tail = 0;
162    }
163
164    _state |= kHIDQueueStarted;
165
166START_END:
167    if ( _lock )
168        IOLockUnlock(_lock);
169
170}
171
172void IOHIDEventQueue::stop()
173{
174    if ( _lock )
175        IOLockLock(_lock);
176
177    _state &= ~kHIDQueueStarted;
178
179    if ( _lock )
180        IOLockUnlock(_lock);
181}
182
183void IOHIDEventQueue::enable()
184{
185    if ( _lock )
186        IOLockLock(_lock);
187
188    _state &= ~kHIDQueueDisabled;
189
190    if ( _lock )
191        IOLockUnlock(_lock);
192}
193
194void IOHIDEventQueue::disable()
195{
196    if ( _lock )
197        IOLockLock(_lock);
198
199    _state |= kHIDQueueDisabled;
200
201    if ( _lock )
202        IOLockUnlock(_lock);
203}
204
205Boolean IOHIDEventQueue::isStarted()
206{
207    bool ret;
208
209    if ( _lock )
210        IOLockLock(_lock);
211
212    ret = (_state & kHIDQueueStarted) != 0;
213
214    if ( _lock )
215        IOLockUnlock(_lock);
216
217    return ret;
218}
219
220void IOHIDEventQueue::setOptions(IOHIDQueueOptionsType flags)
221{
222    if ( _lock )
223        IOLockLock(_lock);
224
225	_options = flags;
226
227    if ( _lock )
228        IOLockUnlock(_lock);
229}
230
231IOHIDQueueOptionsType IOHIDEventQueue::getOptions()
232{
233	return _options;
234}
235
236//---------------------------------------------------------------------------
237// Add element to the queue.
238
239void IOHIDEventQueue::addElement( IOHIDElementPrivate * element )
240{
241    UInt32 elementSize;
242
243    if ( !element )
244        return;
245
246    if ( !_elementSet )
247    {
248        _elementSet = OSSet::withCapacity(4);
249    }
250
251    if ( _elementSet->containsObject( element ) )
252        return;
253
254    elementSize = element->getElementValueSize() + sizeof(void *);
255
256    if ( _maxEntrySize < elementSize )
257        _maxEntrySize = elementSize;
258}
259
260//---------------------------------------------------------------------------
261// Remove element from the queue.
262
263void IOHIDEventQueue::removeElement( IOHIDElementPrivate * element )
264{
265    OSCollectionIterator *      iterator;
266    IOHIDElementPrivate *       temp;
267    UInt32                      size        = 0;
268    UInt32                      maxSize     = DEFAULT_HID_ENTRY_SIZE;
269
270    if ( !element || !_elementSet || !_elementSet->containsObject( element ))
271        return;
272
273    _elementSet->removeObject( element );
274
275    if ( NULL != (iterator = OSCollectionIterator::withCollection(_elementSet)) )
276    {
277        while ( NULL != (temp = (IOHIDElementPrivate *)iterator->getNextObject()) )
278        {
279            size = temp->getElementValueSize() + sizeof(void *);
280
281            if ( maxSize < size )
282                maxSize = size;
283        }
284
285        iterator->release();
286    }
287
288    _maxEntrySize = maxSize;
289}
290
291//---------------------------------------------------------------------------
292// get entry size from the queue.
293
294UInt32 IOHIDEventQueue::getEntrySize( )
295{
296    return _maxEntrySize;
297}
298
299
300//---------------------------------------------------------------------------
301// get a mem descriptor.  replacing default behavior
302
303IOMemoryDescriptor * IOHIDEventQueue::getMemoryDescriptor()
304{
305    if (!_descriptor)
306        _descriptor = super::getMemoryDescriptor();
307
308    return _descriptor;
309}
310
311//---------------------------------------------------------------------------
312//
313
314OSMetaClassDefineReservedUnused(IOHIDEventQueue,  0);
315OSMetaClassDefineReservedUnused(IOHIDEventQueue,  1);
316OSMetaClassDefineReservedUnused(IOHIDEventQueue,  2);
317OSMetaClassDefineReservedUnused(IOHIDEventQueue,  3);
318OSMetaClassDefineReservedUnused(IOHIDEventQueue,  4);
319OSMetaClassDefineReservedUnused(IOHIDEventQueue,  5);
320OSMetaClassDefineReservedUnused(IOHIDEventQueue,  6);
321OSMetaClassDefineReservedUnused(IOHIDEventQueue,  7);
322OSMetaClassDefineReservedUnused(IOHIDEventQueue,  8);
323OSMetaClassDefineReservedUnused(IOHIDEventQueue,  9);
324OSMetaClassDefineReservedUnused(IOHIDEventQueue, 10);
325OSMetaClassDefineReservedUnused(IOHIDEventQueue, 11);
326OSMetaClassDefineReservedUnused(IOHIDEventQueue, 12);
327OSMetaClassDefineReservedUnused(IOHIDEventQueue, 13);
328OSMetaClassDefineReservedUnused(IOHIDEventQueue, 14);
329OSMetaClassDefineReservedUnused(IOHIDEventQueue, 15);
330