2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/IODataQueue.h>
24 #include <IOKit/IODataQueueShared.h>
25 #include <IOKit/IOLib.h>
26 #include <IOKit/IOMemoryDescriptor.h>
36 #define super OSObject
38 OSDefineMetaClassAndStructors(IODataQueue
, OSObject
)
40 IODataQueue
*IODataQueue::withCapacity(UInt32 size
)
42 IODataQueue
*dataQueue
= new IODataQueue
;
45 if (!dataQueue
->initWithCapacity(size
)) {
54 IODataQueue
*IODataQueue::withEntries(UInt32 numEntries
, UInt32 entrySize
)
56 IODataQueue
*dataQueue
= new IODataQueue
;
59 if (!dataQueue
->initWithEntries(numEntries
, entrySize
)) {
68 Boolean
IODataQueue::initWithCapacity(UInt32 size
)
74 dataQueue
= (IODataQueueMemory
*)IOMallocAligned(round_page(size
+ DATA_QUEUE_MEMORY_HEADER_SIZE
), PAGE_SIZE
);
79 dataQueue
->queueSize
= size
;
86 Boolean
IODataQueue::initWithEntries(UInt32 numEntries
, UInt32 entrySize
)
88 return (initWithCapacity((numEntries
+ 1) * (DATA_QUEUE_ENTRY_HEADER_SIZE
+ entrySize
)));
91 void IODataQueue::free()
94 IOFreeAligned(dataQueue
, round_page(dataQueue
->queueSize
+ DATA_QUEUE_MEMORY_HEADER_SIZE
));
102 Boolean
IODataQueue::enqueue(void * data
, UInt32 dataSize
)
104 const UInt32 head
= dataQueue
->head
; // volatile
105 const UInt32 tail
= dataQueue
->tail
;
106 const UInt32 entrySize
= dataSize
+ DATA_QUEUE_ENTRY_HEADER_SIZE
;
107 IODataQueueEntry
* entry
;
111 if ( (tail
+ entrySize
) < dataQueue
->queueSize
)
113 entry
= (IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
);
115 entry
->size
= dataSize
;
116 memcpy(&entry
->data
, data
, dataSize
);
117 dataQueue
->tail
+= entrySize
;
119 else if ( head
> entrySize
)
121 // Wrap around to the beginning, but do not allow the tail to catch
124 dataQueue
->queue
->size
= dataSize
;
125 ((IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
))->size
= dataSize
;
126 memcpy(&dataQueue
->queue
->data
, data
, dataSize
);
127 dataQueue
->tail
= entrySize
;
131 return false; // queue is full
136 // Do not allow the tail to catch up to the head when the queue is full.
137 // That's why the comparison uses a '>' rather than '>='.
139 if ( (head
- tail
) > entrySize
)
141 entry
= (IODataQueueEntry
*)((UInt8
*)dataQueue
->queue
+ tail
);
143 entry
->size
= dataSize
;
144 memcpy(&entry
->data
, data
, dataSize
);
145 dataQueue
->tail
+= entrySize
;
149 return false; // queue is full
153 // Send notification (via mach message) that data is available.
155 if ( ( head
== tail
) /* queue was empty prior to enqueue() */
156 || ( dataQueue
->head
== tail
) ) /* queue was emptied during enqueue() */
158 sendDataAvailableNotification();
164 void IODataQueue::setNotificationPort(mach_port_t port
)
166 static struct _notifyMsg init_msg
= { {
167 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0),
168 sizeof (struct _notifyMsg
),
175 if (notifyMsg
== 0) {
176 notifyMsg
= IOMalloc(sizeof(struct _notifyMsg
));
179 *((struct _notifyMsg
*)notifyMsg
) = init_msg
;
181 ((struct _notifyMsg
*)notifyMsg
)->h
.msgh_remote_port
= port
;
184 void IODataQueue::sendDataAvailableNotification()
187 mach_msg_header_t
* msgh
;
189 msgh
= (mach_msg_header_t
*)notifyMsg
;
191 kr
= mach_msg_send_from_kernel(msgh
, msgh
->msgh_size
);
193 case MACH_SEND_TIMED_OUT
: // Notification already sent
194 case MACH_MSG_SUCCESS
:
197 IOLog("%s: dataAvailableNotification failed - msg_send returned: %d\n", /*getName()*/"IODataQueue", kr
);
203 IOMemoryDescriptor
*IODataQueue::getMemoryDescriptor()
205 IOMemoryDescriptor
*descriptor
= 0;
207 if (dataQueue
!= 0) {
208 descriptor
= IOMemoryDescriptor::withAddress(dataQueue
, dataQueue
->queueSize
+ DATA_QUEUE_MEMORY_HEADER_SIZE
, kIODirectionOutIn
);