2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include <IOKit/IODataQueue.h>
27 #include <IOKit/IODataQueueShared.h>
28 #include <IOKit/IOLib.h>
29 #include <IOKit/IOMemoryDescriptor.h>
39 #define super OSObject
41 OSDefineMetaClassAndStructors(IODataQueue
, OSObject
)
43 IODataQueue
*IODataQueue::withCapacity(UInt32 size
)
45 IODataQueue
*dataQueue
= new IODataQueue
;
48 if (!dataQueue
->initWithCapacity(size
)) {
57 IODataQueue
*IODataQueue::withEntries(UInt32 numEntries
, UInt32 entrySize
)
59 IODataQueue
*dataQueue
= new IODataQueue
;
62 if (!dataQueue
->initWithEntries(numEntries
, entrySize
)) {
71 Boolean
IODataQueue::initWithCapacity(UInt32 size
)
77 dataQueue
= (IODataQueueMemory
*)IOMallocAligned(round_page_32(size
+ DATA_QUEUE_MEMORY_HEADER_SIZE
), PAGE_SIZE
);
82 dataQueue
->queueSize
= size
;
89 Boolean
IODataQueue::initWithEntries(UInt32 numEntries
, UInt32 entrySize
)
91 return (initWithCapacity((numEntries
+ 1) * (DATA_QUEUE_ENTRY_HEADER_SIZE
+ entrySize
)));
94 void IODataQueue::free()
97 IOFreeAligned(dataQueue
, round_page_32(dataQueue
->queueSize
+ DATA_QUEUE_MEMORY_HEADER_SIZE
));
105 Boolean
IODataQueue::enqueue(void * data
, UInt32 dataSize
)
107 const UInt32 head
= dataQueue
->head
; // volatile
108 const UInt32 tail
= dataQueue
->tail
;
109 const UInt32 entrySize
= dataSize
+ DATA_QUEUE_ENTRY_HEADER_SIZE
;
110 IODataQueueEntry
* entry
;
114 // Is there enough room at the end for the entry?
115 if ( (tail
+ entrySize
) <= dataQueue
->queueSize
)
117 entry
= (IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
);
119 entry
->size
= dataSize
;
120 memcpy(&entry
->data
, data
, dataSize
);
122 // The tail can be out of bound when the size of the new entry
123 // exactly matches the available space at the end of the queue.
124 // The tail can range from 0 to dataQueue->queueSize inclusive.
126 dataQueue
->tail
+= entrySize
;
128 else if ( head
> entrySize
) // Is there enough room at the beginning?
130 // Wrap around to the beginning, but do not allow the tail to catch
133 dataQueue
->queue
->size
= dataSize
;
135 // We need to make sure that there is enough room to set the size before
136 // doing this. The user client checks for this and will look for the size
137 // at the beginning if there isn't room for it at the end.
139 if ( ( dataQueue
->queueSize
- tail
) >= DATA_QUEUE_ENTRY_HEADER_SIZE
)
141 ((IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
))->size
= dataSize
;
144 memcpy(&dataQueue
->queue
->data
, data
, dataSize
);
145 dataQueue
->tail
= entrySize
;
149 return false; // queue is full
154 // Do not allow the tail to catch up to the head when the queue is full.
155 // That's why the comparison uses a '>' rather than '>='.
157 if ( (head
- tail
) > entrySize
)
159 entry
= (IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
);
161 entry
->size
= dataSize
;
162 memcpy(&entry
->data
, data
, dataSize
);
163 dataQueue
->tail
+= entrySize
;
167 return false; // queue is full
171 // Send notification (via mach message) that data is available.
173 if ( ( head
== tail
) /* queue was empty prior to enqueue() */
174 || ( dataQueue
->head
== tail
) ) /* queue was emptied during enqueue() */
176 sendDataAvailableNotification();
182 void IODataQueue::setNotificationPort(mach_port_t port
)
184 static struct _notifyMsg init_msg
= { {
185 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0),
186 sizeof (struct _notifyMsg
),
193 if (notifyMsg
== 0) {
194 notifyMsg
= IOMalloc(sizeof(struct _notifyMsg
));
197 *((struct _notifyMsg
*)notifyMsg
) = init_msg
;
199 ((struct _notifyMsg
*)notifyMsg
)->h
.msgh_remote_port
= port
;
202 void IODataQueue::sendDataAvailableNotification()
205 mach_msg_header_t
* msgh
;
207 msgh
= (mach_msg_header_t
*)notifyMsg
;
209 kr
= mach_msg_send_from_kernel(msgh
, msgh
->msgh_size
);
211 case MACH_SEND_TIMED_OUT
: // Notification already sent
212 case MACH_MSG_SUCCESS
:
215 IOLog("%s: dataAvailableNotification failed - msg_send returned: %d\n", /*getName()*/"IODataQueue", kr
);
221 IOMemoryDescriptor
*IODataQueue::getMemoryDescriptor()
223 IOMemoryDescriptor
*descriptor
= 0;
225 if (dataQueue
!= 0) {
226 descriptor
= IOMemoryDescriptor::withAddress(dataQueue
, dataQueue
->queueSize
+ DATA_QUEUE_MEMORY_HEADER_SIZE
, kIODirectionOutIn
);