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