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 <IOKit/IOMemoryDescriptor.h>
28#include <libkern/OSAtomic.h>
29#undef enqueue
30#include "IOHIDEventServiceQueue.h"
31#include "IOHIDEvent.h"
32
33#define super IOSharedDataQueue
34OSDefineMetaClassAndStructors( IOHIDEventServiceQueue, super )
35
36IOHIDEventServiceQueue *IOHIDEventServiceQueue::withCapacity(UInt32 size)
37{
38    IOHIDEventServiceQueue *dataQueue = new IOHIDEventServiceQueue;
39
40    if (dataQueue) {
41        if  (!dataQueue->initWithCapacity(size)) {
42            dataQueue->release();
43            dataQueue = 0;
44        }
45    }
46
47    return dataQueue;
48}
49
50void IOHIDEventServiceQueue::free()
51{
52    if ( _descriptor )
53    {
54        _descriptor->release();
55        _descriptor = 0;
56    }
57
58    super::free();
59}
60
61//---------------------------------------------------------------------------
62// Add event to the queue.
63
64Boolean IOHIDEventServiceQueue::enqueueEvent( IOHIDEvent * event )
65{
66    IOByteCount         dataSize  = event->getLength();
67    const UInt32        head      = dataQueue->head;  // volatile
68    const UInt32        tail      = dataQueue->tail;
69    const UInt32        entrySize = dataSize + DATA_QUEUE_ENTRY_HEADER_SIZE;
70    IODataQueueEntry *  entry;
71    bool                queueFull = false;
72    bool                result    = true;
73
74    if ( tail >= head )
75    {
76        // Is there enough room at the end for the entry?
77        if ( (tail + entrySize) <= getQueueSize() )
78        {
79            entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail);
80
81            entry->size = dataSize;
82            event->readBytes(&entry->data, dataSize);
83
84            // The tail can be out of bound when the size of the new entry
85            // exactly matches the available space at the end of the queue.
86            // The tail can range from 0 to getQueueSize() inclusive.
87
88            // RY: effectively performs a memory barrier
89            OSAddAtomic(entrySize, (SInt32 *)&dataQueue->tail);
90        }
91        else if ( head > entrySize ) 	// Is there enough room at the beginning?
92        {
93            // Wrap around to the beginning, but do not allow the tail to catch
94            // up to the head.
95
96            dataQueue->queue->size = dataSize;
97
98            // We need to make sure that there is enough room to set the size before
99            // doing this. The user client checks for this and will look for the size
100            // at the beginning if there isn't room for it at the end.
101
102            if ( ( getQueueSize() - tail ) >= DATA_QUEUE_ENTRY_HEADER_SIZE )
103            {
104                ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize;
105            }
106
107            event->readBytes(&dataQueue->queue->data, dataSize);
108
109            // RY: effectively performs a memory barrier
110            OSCompareAndSwap(dataQueue->tail, entrySize, &dataQueue->tail);
111        }
112        else
113        {
114            queueFull = true;
115            result = false;	// queue is full
116        }
117    }
118    else
119    {
120        // Do not allow the tail to catch up to the head when the queue is full.
121        // That's why the comparison uses a '>' rather than '>='.
122
123        if ( (head - tail) > entrySize )
124        {
125            entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail);
126
127            entry->size = dataSize;
128            event->readBytes(&entry->data, dataSize);
129
130            // RY: effectively performs a memory barrier
131            OSAddAtomic(entrySize, (SInt32 *)&dataQueue->tail);
132        }
133        else
134        {
135            queueFull = true;
136            result = false;	// queue is full
137        }
138    }
139
140    // Send notification (via mach message) that data is available if either the
141    // queue was empty prior to enqueue() or queue was emptied during enqueue()
142    if ( ( head == tail ) || ( dataQueue->head == tail ) || queueFull) {
143//        if (queueFull) {
144//            IOLog("IOHIDEventServiceQueue::enqueueEvent - Queue is full, notifying again\n");
145//        }
146        sendDataAvailableNotification();
147    }
148
149    return result;
150}
151
152
153//---------------------------------------------------------------------------
154// set the notification port
155
156void IOHIDEventServiceQueue::setNotificationPort(mach_port_t port) {
157    super::setNotificationPort(port);
158
159    if (dataQueue->head != dataQueue->tail)
160        sendDataAvailableNotification();
161}
162
163//---------------------------------------------------------------------------
164// get a mem descriptor.  replacing default behavior
165
166IOMemoryDescriptor * IOHIDEventServiceQueue::getMemoryDescriptor()
167{
168    if (!_descriptor)
169        _descriptor = super::getMemoryDescriptor();
170
171    return _descriptor;
172}
173
174//---------------------------------------------------------------------------
175