IOUSBHIDDataQueue.cpp [plain text]
#include <IOKit/IODataQueueShared.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/usb/IOUSBHIDDataQueue.h>
#define super OSObject
OSDefineMetaClassAndStructors(IOUSBHIDDataQueue, super)
IOUSBHIDDataQueue *IOUSBHIDDataQueue::withCapacity(UInt32 size)
{
IOUSBHIDDataQueue *dataQueue = new IOUSBHIDDataQueue;
if (dataQueue) {
if (!dataQueue->initWithCapacity(size)) {
dataQueue->release();
dataQueue = 0;
}
}
return dataQueue;
}
IOUSBHIDDataQueue *IOUSBHIDDataQueue::withEntries(UInt32 numEntries, UInt32 entrySize)
{
IOUSBHIDDataQueue *dataQueue = new IOUSBHIDDataQueue;
if (dataQueue) {
if (!dataQueue->initWithEntries(numEntries, entrySize)) {
dataQueue->release();
dataQueue = 0;
}
}
return dataQueue;
}
Boolean IOUSBHIDDataQueue::initWithCapacity(UInt32 size)
{
if (!super::init()) {
return false;
}
dataQueue = (IODataQueueMemory *)IOMallocAligned(round_page(size + DATA_QUEUE_MEMORY_HEADER_SIZE), PAGE_SIZE);
if (dataQueue == 0) {
return false;
}
dataQueue->queueSize = size;
dataQueue->head = 0;
dataQueue->tail = 0;
return true;
}
Boolean IOUSBHIDDataQueue::initWithEntries(UInt32 numEntries, UInt32 entrySize)
{
return (initWithCapacity(numEntries * (DATA_QUEUE_ENTRY_HEADER_SIZE + entrySize)));
}
void IOUSBHIDDataQueue::free()
{
if (dataQueue) {
IOFreeAligned(dataQueue, round_page(dataQueue->queueSize + DATA_QUEUE_MEMORY_HEADER_SIZE));
}
super::free();
return;
}
Boolean
IOUSBHIDDataQueue::enqueue(void *data, UInt32 dataSize)
{
IODataQueueEntry *head, *tail;
UInt32 headVal;
if ((dataQueue->tail + DATA_QUEUE_ENTRY_HEADER_SIZE + dataSize) <= dataQueue->queueSize) {
tail = (IODataQueueEntry *)((char *)dataQueue->queue + dataQueue->tail);
tail->size = dataSize;
memcpy(&tail->data, data, dataSize);
dataQueue->tail += DATA_QUEUE_ENTRY_HEADER_SIZE + dataSize;
} else if (dataQueue->head >= (DATA_QUEUE_ENTRY_HEADER_SIZE + dataSize)) { dataQueue->queue->size = dataSize;
((IODataQueueEntry *)((char *)dataQueue->queue + dataQueue->tail))->size = dataSize;
memcpy(&dataQueue->queue->data, data, dataSize);
dataQueue->tail = DATA_QUEUE_ENTRY_HEADER_SIZE + dataSize;
} else {
return false;
}
headVal = dataQueue->head;
tail = (IODataQueueEntry *)((char *)dataQueue->queue + dataQueue->tail);
head = (IODataQueueEntry *)((char *)dataQueue->queue + headVal);
if (((headVal + head->size + DATA_QUEUE_ENTRY_HEADER_SIZE) == dataQueue->tail)
|| (((headVal + head->size + DATA_QUEUE_ENTRY_HEADER_SIZE) > dataQueue->queueSize)
&& (dataQueue->queue->size == dataQueue->tail))) {
sendDataAvailableNotification();
}
return true;
}
void IOUSBHIDDataQueue::setNotificationPort(mach_port_t port)
{
static struct _hidnotifyMsg init_msg = { {
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0),
sizeof (struct _hidnotifyMsg),
MACH_PORT_NULL,
MACH_PORT_NULL,
0,
0
} };
if (notifyMsg == 0) {
notifyMsg = IOMalloc(sizeof(struct _hidnotifyMsg));
}
*((struct _hidnotifyMsg *)notifyMsg) = init_msg;
((struct _hidnotifyMsg *)notifyMsg)->h.msgh_remote_port = port;
}
void IOUSBHIDDataQueue::sendDataAvailableNotification()
{
kern_return_t kr;
mach_msg_header_t * msgh;
msgh = (mach_msg_header_t *)notifyMsg;
if (msgh) {
kr = mach_msg_send_from_kernel(msgh, msgh->msgh_size);
switch(kr) {
case MACH_SEND_TIMED_OUT: case MACH_MSG_SUCCESS:
break;
default:
IOLog("%s: dataAvailableNotification failed - msg_send returned: %d\n", "IOUSBHIDDataQueue", kr);
break;
}
}
}
IOMemoryDescriptor *IOUSBHIDDataQueue::getMemoryDescriptor()
{
IOMemoryDescriptor *descriptor = 0;
if (dataQueue != 0) {
descriptor = IOMemoryDescriptor::withAddress(dataQueue, dataQueue->queueSize + DATA_QUEUE_MEMORY_HEADER_SIZE, kIODirectionOutIn);
}
return descriptor;
}