293 lines
5.9 KiB
C
293 lines
5.9 KiB
C
/*****************************************************************************
|
|
|
|
(c) Cambridge Silicon Radio Limited 2010
|
|
All rights reserved and confidential information of CSR
|
|
|
|
Refer to LICENSE.txt included with this source for details
|
|
on the license terms.
|
|
|
|
*****************************************************************************/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include "csr_panic.h"
|
|
#include "csr_sched.h"
|
|
#include "csr_msgconv.h"
|
|
#include "csr_macro.h"
|
|
|
|
static CsrMsgConvEntry *converter;
|
|
|
|
CsrMsgConvPrimEntry *CsrMsgConvFind(u16 primType)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr = NULL;
|
|
|
|
if (converter)
|
|
{
|
|
ptr = converter->profile_converters;
|
|
while (ptr)
|
|
{
|
|
if (ptr->primType == primType)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static const CsrMsgConvMsgEntry *find_msg_converter(CsrMsgConvPrimEntry *ptr, u16 msgType)
|
|
{
|
|
const CsrMsgConvMsgEntry *cv = ptr->conv;
|
|
if (ptr->lookupFunc)
|
|
{
|
|
return (const CsrMsgConvMsgEntry *) ptr->lookupFunc((CsrMsgConvMsgEntry *) cv, msgType);
|
|
}
|
|
|
|
while (cv)
|
|
{
|
|
if (cv->serFunc == NULL)
|
|
{
|
|
/* We've reached the end of the chain */
|
|
cv = NULL;
|
|
break;
|
|
}
|
|
|
|
if (cv->msgType == msgType)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
cv++;
|
|
}
|
|
}
|
|
|
|
return cv;
|
|
}
|
|
|
|
static void *deserialize_data(u16 primType,
|
|
size_t length,
|
|
u8 *data)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr;
|
|
u8 *ret;
|
|
|
|
ptr = CsrMsgConvFind(primType);
|
|
|
|
if (ptr)
|
|
{
|
|
const CsrMsgConvMsgEntry *cv;
|
|
u16 msgId = 0;
|
|
size_t offset = 0;
|
|
CsrUint16Des(&msgId, data, &offset);
|
|
|
|
cv = find_msg_converter(ptr, msgId);
|
|
if (cv)
|
|
{
|
|
ret = cv->deserFunc(data, length);
|
|
}
|
|
else
|
|
{
|
|
ret = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static size_t sizeof_message(u16 primType, void *msg)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
|
|
size_t ret;
|
|
|
|
if (ptr)
|
|
{
|
|
const CsrMsgConvMsgEntry *cv;
|
|
u16 msgId = *(u16 *) msg;
|
|
|
|
cv = find_msg_converter(ptr, msgId);
|
|
if (cv)
|
|
{
|
|
ret = cv->sizeofFunc(msg);
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static u8 free_message(u16 primType, u8 *data)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr;
|
|
u8 ret;
|
|
|
|
ptr = CsrMsgConvFind(primType);
|
|
|
|
if (ptr)
|
|
{
|
|
const CsrMsgConvMsgEntry *cv;
|
|
u16 msgId = *(u16 *) data;
|
|
|
|
cv = find_msg_converter(ptr, msgId);
|
|
if (cv)
|
|
{
|
|
cv->freeFunc(data);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ret = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = FALSE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static u8 *serialize_message(u16 primType,
|
|
void *msg,
|
|
size_t *length,
|
|
u8 *buffer)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr;
|
|
u8 *ret;
|
|
|
|
ptr = CsrMsgConvFind(primType);
|
|
|
|
*length = 0;
|
|
|
|
if (ptr)
|
|
{
|
|
const CsrMsgConvMsgEntry *cv;
|
|
|
|
cv = find_msg_converter(ptr, *(u16 *) msg);
|
|
if (cv)
|
|
{
|
|
ret = cv->serFunc(buffer, length, msg);
|
|
}
|
|
else
|
|
{
|
|
ret = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
size_t CsrMsgConvSizeof(u16 primType, void *msg)
|
|
{
|
|
return sizeof_message(primType, msg);
|
|
}
|
|
|
|
u8 *CsrMsgConvSerialize(u8 *buffer, size_t maxBufferOffset, size_t *offset, u16 primType, void *msg)
|
|
{
|
|
if (converter)
|
|
{
|
|
size_t serializedLength;
|
|
u8 *bufSerialized;
|
|
u8 *bufOffset = &buffer[*offset];
|
|
bufSerialized = converter->serialize_message(primType, msg, &serializedLength, bufOffset);
|
|
*offset += serializedLength;
|
|
return bufSerialized;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Insert profile converter at head of converter list. */
|
|
void CsrMsgConvInsert(u16 primType, const CsrMsgConvMsgEntry *ce)
|
|
{
|
|
CsrMsgConvPrimEntry *pc;
|
|
pc = CsrMsgConvFind(primType);
|
|
|
|
if (pc)
|
|
{
|
|
/* Already registered. Do nothing */
|
|
}
|
|
else
|
|
{
|
|
pc = kmalloc(sizeof(*pc), GFP_KERNEL);
|
|
pc->primType = primType;
|
|
pc->conv = ce;
|
|
pc->lookupFunc = NULL;
|
|
pc->next = converter->profile_converters;
|
|
converter->profile_converters = pc;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(CsrMsgConvInsert);
|
|
|
|
CsrMsgConvMsgEntry *CsrMsgConvFindEntry(u16 primType, u16 msgType)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
|
|
if (ptr)
|
|
{
|
|
return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType);
|
|
}
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(CsrMsgConvFindEntry);
|
|
|
|
CsrMsgConvMsgEntry *CsrMsgConvFindEntryByMsg(u16 primType, const void *msg)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
|
|
if (ptr && msg)
|
|
{
|
|
u16 msgType = *((u16 *) msg);
|
|
return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CsrMsgConvCustomLookupRegister(u16 primType, CsrMsgCustomLookupFunc *lookupFunc)
|
|
{
|
|
CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
|
|
if (ptr)
|
|
{
|
|
ptr->lookupFunc = lookupFunc;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(CsrMsgConvCustomLookupRegister);
|
|
|
|
CsrMsgConvEntry *CsrMsgConvInit(void)
|
|
{
|
|
if (!converter)
|
|
{
|
|
converter = kmalloc(sizeof(CsrMsgConvEntry), GFP_KERNEL);
|
|
|
|
converter->profile_converters = NULL;
|
|
converter->free_message = free_message;
|
|
converter->sizeof_message = sizeof_message;
|
|
converter->serialize_message = serialize_message;
|
|
converter->deserialize_data = deserialize_data;
|
|
}
|
|
|
|
return converter;
|
|
}
|
|
EXPORT_SYMBOL_GPL(CsrMsgConvInit);
|