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 
40 OSDefineMetaClassAndStructors(IOSharedDataQueue, IODataQueue)
41 
42 IOSharedDataQueue *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 
56 IOSharedDataQueue *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 
70 Boolean 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 
95 void 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 
105 IOMemoryDescriptor *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 
117 IODataQueueEntry * 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 
147 Boolean 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 
210 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 0);
211 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 1);
212 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 2);
213 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 3);
214 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 4);
215 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 5);
216 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 6);
217 OSMetaClassDefineReservedUnused(IOSharedDataQueue, 7);
218