1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <IOKit/IOSharedDataQueue.h>
30#include <IOKit/IODataQueueShared.h>
31#include <IOKit/IOLib.h>
32#include <IOKit/IOMemoryDescriptor.h>
33
34#ifdef dequeue
35#undef dequeue
36#endif
37
38#define super IODataQueue
39
40OSDefineMetaClassAndStructors(IOSharedDataQueue, IODataQueue)
41
42IOSharedDataQueue *IOSharedDataQueue::withCapacity(UInt32 size)
43{
44    IOSharedDataQueue *dataQueue = new IOSharedDataQueue;
45
46    if (dataQueue) {
47        if  (!dataQueue->initWithCapacity(size)) {
48            dataQueue->release();
49            dataQueue = 0;
50        }
51    }
52
53    return dataQueue;
54}
55
56IOSharedDataQueue *IOSharedDataQueue::withEntries(UInt32 numEntries, UInt32 entrySize)
57{
58    IOSharedDataQueue *dataQueue = new IOSharedDataQueue;
59
60    if (dataQueue) {
61        if (!dataQueue->initWithEntries(numEntries, entrySize)) {
62            dataQueue->release();
63            dataQueue = 0;
64        }
65    }
66
67    return dataQueue;
68}
69
70Boolean IOSharedDataQueue::initWithCapacity(UInt32 size)
71{
72    IODataQueueAppendix *   appendix;
73
74    if (!super::init()) {
75        return false;
76    }
77
78    dataQueue = (IODataQueueMemory *)IOMallocAligned(round_page(size + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE), PAGE_SIZE);
79    if (dataQueue == 0) {
80        return false;
81    }
82
83    dataQueue->queueSize    = size;
84    dataQueue->head         = 0;
85    dataQueue->tail         = 0;
86
87    appendix            = (IODataQueueAppendix *)((UInt8 *)dataQueue + size + DATA_QUEUE_MEMORY_HEADER_SIZE);
88    appendix->version   = 0;
89    notifyMsg           = &(appendix->msgh);
90    setNotificationPort(MACH_PORT_NULL);
91
92    return true;
93}
94
95void IOSharedDataQueue::free()
96{
97    if (dataQueue) {
98        IOFreeAligned(dataQueue, round_page(dataQueue->queueSize + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE));
99        dataQueue = NULL;
100    }
101
102    super::free();
103}
104
105IOMemoryDescriptor *IOSharedDataQueue::getMemoryDescriptor()
106{
107    IOMemoryDescriptor *descriptor = 0;
108
109    if (dataQueue != 0) {
110        descriptor = IOMemoryDescriptor::withAddress(dataQueue, dataQueue->queueSize + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE, kIODirectionOutIn);
111    }
112
113    return descriptor;
114}
115
116
117IODataQueueEntry * IOSharedDataQueue::peek()
118{
119    IODataQueueEntry *entry = 0;
120
121    if (dataQueue && (dataQueue->head != dataQueue->tail)) {
122        IODataQueueEntry *  head		= 0;
123        UInt32              headSize    = 0;
124        UInt32              headOffset  = dataQueue->head;
125        UInt32              queueSize   = dataQueue->queueSize;
126
127        head 		= (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
128        headSize 	= head->size;
129
130		// Check if there's enough room before the end of the queue for a header.
131        // If there is room, check if there's enough room to hold the header and
132        // the data.
133
134        if ((headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
135            ((headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE) > queueSize))
136        {
137            // No room for the header or the data, wrap to the beginning of the queue.
138            entry = dataQueue->queue;
139        } else {
140            entry = head;
141        }
142    }
143
144    return entry;
145}
146
147Boolean IOSharedDataQueue::dequeue(void *data, UInt32 *dataSize)
148{
149    Boolean             retVal          = TRUE;
150    IODataQueueEntry *  entry           = 0;
151    UInt32              entrySize       = 0;
152    UInt32              newHeadOffset   = 0;
153
154    if (dataQueue) {
155        if (dataQueue->head != dataQueue->tail) {
156            IODataQueueEntry *  head		= 0;
157            UInt32              headSize    = 0;
158            UInt32              headOffset  = dataQueue->head;
159            UInt32              queueSize   = dataQueue->queueSize;
160
161            head 		= (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
162            headSize 	= head->size;
163
164            // we wraped around to beginning, so read from there
165			// either there was not even room for the header
166			if ((headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
167				// or there was room for the header, but not for the data
168				((headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE) > queueSize)) {
169                entry           = dataQueue->queue;
170                entrySize       = entry->size;
171                newHeadOffset   = entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
172            // else it is at the end
173            } else {
174                entry           = head;
175                entrySize       = entry->size;
176                newHeadOffset   = headOffset + entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
177            }
178        }
179
180        if (entry) {
181            if (data) {
182                if (dataSize) {
183                    if (entrySize <= *dataSize) {
184                        memcpy(data, &(entry->data), entrySize);
185                        dataQueue->head = newHeadOffset;
186                    } else {
187                        retVal = FALSE;
188                    }
189                } else {
190                    retVal = FALSE;
191                }
192            } else {
193                dataQueue->head = newHeadOffset;
194            }
195
196            if (dataSize) {
197                *dataSize = entrySize;
198            }
199        } else {
200            retVal = FALSE;
201        }
202    } else {
203        retVal = FALSE;
204    }
205
206    return retVal;
207}
208
209
210OSMetaClassDefineReservedUnused(IOSharedDataQueue, 0);
211OSMetaClassDefineReservedUnused(IOSharedDataQueue, 1);
212OSMetaClassDefineReservedUnused(IOSharedDataQueue, 2);
213OSMetaClassDefineReservedUnused(IOSharedDataQueue, 3);
214OSMetaClassDefineReservedUnused(IOSharedDataQueue, 4);
215OSMetaClassDefineReservedUnused(IOSharedDataQueue, 5);
216OSMetaClassDefineReservedUnused(IOSharedDataQueue, 6);
217OSMetaClassDefineReservedUnused(IOSharedDataQueue, 7);
218