IODataQueueClient.c [plain text]
#include <IOKit/IODataQueueClient.h>
#include <IOKit/IODataQueueShared.h>
#include <mach/message.h>
#include <mach/mach_port.h>
#include <mach/port.h>
#include <mach/mach_init.h>
#include <IOKit/OSMessageNotification.h>
#include <System/libkern/OSCrossEndian.h>
Boolean IODataQueueDataAvailable(IODataQueueMemory *dataQueue)
{
return (dataQueue && (dataQueue->head != dataQueue->tail));
}
IODataQueueEntry *IODataQueuePeek(IODataQueueMemory *dataQueue)
{
IODataQueueEntry *entry = 0;
if (dataQueue && (dataQueue->head != dataQueue->tail)) {
IODataQueueEntry * head = 0;
UInt32 headSize = 0;
UInt32 headOffset = dataQueue->head;
UInt32 queueSize = dataQueue->queueSize;
ROSETTA_ONLY(
headOffset = OSSwapInt32(headOffset);
queueSize = OSSwapInt32(queueSize);
);
head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
headSize = head->size;
ROSETTA_ONLY(
headSize = OSSwapInt32(headSize);
);
if ((headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
((headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE) > queueSize))
{
entry = dataQueue->queue;
} else {
entry = head;
}
}
return entry;
}
IOReturn IODataQueueDequeue(IODataQueueMemory *dataQueue, void *data, UInt32 *dataSize)
{
IOReturn retVal = kIOReturnSuccess;
IODataQueueEntry * entry = 0;
UInt32 entrySize = 0;
UInt32 newHeadOffset = 0;
if (dataQueue) {
if (dataQueue->head != dataQueue->tail) {
IODataQueueEntry * head = 0;
UInt32 headSize = 0;
UInt32 headOffset = dataQueue->head;
UInt32 queueSize = dataQueue->queueSize;
ROSETTA_ONLY(
headOffset = OSSwapInt32(headOffset);
queueSize = OSSwapInt32(queueSize);
);
head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
headSize = head->size;
ROSETTA_ONLY(
headSize = OSSwapInt32(headSize);
);
if ((headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
((headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE) > queueSize)) {
entry = dataQueue->queue;
entrySize = entry->size;
ROSETTA_ONLY(
entrySize = OSSwapInt32(entrySize);
);
newHeadOffset = entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
} else {
entry = head;
entrySize = entry->size;
ROSETTA_ONLY(
entrySize = OSSwapInt32(entrySize);
);
newHeadOffset = headOffset + entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
}
}
ROSETTA_ONLY(
newHeadOffset = OSSwapInt32(newHeadOffset);
);
if (entry) {
if (data) {
if (dataSize) {
if (entrySize <= *dataSize) {
memcpy(data, &(entry->data), entrySize);
dataQueue->head = newHeadOffset;
} else {
retVal = kIOReturnNoSpace;
}
} else {
retVal = kIOReturnBadArgument;
}
} else {
dataQueue->head = newHeadOffset;
}
if (dataSize) {
*dataSize = entrySize;
}
} else {
retVal = kIOReturnUnderrun;
}
} else {
retVal = kIOReturnBadArgument;
}
return retVal;
}
IOReturn IODataQueueWaitForAvailableData(IODataQueueMemory *dataQueue, mach_port_t notifyPort)
{
IOReturn kr;
struct {
mach_msg_header_t msgHdr;
OSNotificationHeader notifyHeader;
mach_msg_trailer_t trailer;
} msg;
if (dataQueue && (notifyPort != MACH_PORT_NULL)) {
kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG, 0, sizeof(msg), notifyPort, 0, MACH_PORT_NULL);
} else {
kr = kIOReturnBadArgument;
}
return kr;
}
mach_port_t IODataQueueAllocateNotificationPort()
{
mach_port_t port = MACH_PORT_NULL;
mach_port_limits_t limits;
mach_msg_type_number_t info_cnt;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
info_cnt = MACH_PORT_LIMITS_INFO_COUNT;
mach_port_get_attributes(mach_task_self(),
port,
MACH_PORT_LIMITS_INFO,
(mach_port_info_t)&limits,
&info_cnt);
limits.mpl_qlimit = 1;
mach_port_set_attributes(mach_task_self(),
port,
MACH_PORT_LIMITS_INFO,
(mach_port_info_t)&limits,
MACH_PORT_LIMITS_INFO_COUNT);
return port;
}