diff options
Diffstat (limited to 'drivers/staging/csr/csr_msgconv.c')
-rw-r--r-- | drivers/staging/csr/csr_msgconv.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/drivers/staging/csr/csr_msgconv.c b/drivers/staging/csr/csr_msgconv.c new file mode 100644 index 000000000000..9f1c946c66f9 --- /dev/null +++ b/drivers/staging/csr/csr_msgconv.c @@ -0,0 +1,324 @@ +/***************************************************************************** + + (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 "csr_types.h" +#include "csr_pmem.h" +#include "csr_panic.h" +#include "csr_sched.h" +#include "csr_msgconv.h" +#include "csr_util.h" + +static CsrMsgConvEntry *converter; + +CsrMsgConvPrimEntry *CsrMsgConvFind(CsrUint16 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, CsrUint16 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(CsrUint16 primType, + CsrSize length, + CsrUint8 *data) +{ + CsrMsgConvPrimEntry *ptr; + CsrUint8 *ret; + + ptr = CsrMsgConvFind(primType); + + if (ptr) + { + const CsrMsgConvMsgEntry *cv; + CsrUint16 msgId = 0; + CsrSize 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 CsrSize sizeof_message(CsrUint16 primType, void *msg) +{ + CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); + CsrSize ret; + + if (ptr) + { + const CsrMsgConvMsgEntry *cv; + CsrUint16 msgId = *(CsrUint16 *) msg; + + cv = find_msg_converter(ptr, msgId); + if (cv) + { + ret = cv->sizeofFunc(msg); + } + else + { + ret = 0; + } + } + else + { + ret = 0; + } + + return ret; +} + +static CsrBool free_message(CsrUint16 primType, CsrUint8 *data) +{ + CsrMsgConvPrimEntry *ptr; + CsrBool ret; + + ptr = CsrMsgConvFind(primType); + + if (ptr) + { + const CsrMsgConvMsgEntry *cv; + CsrUint16 msgId = *(CsrUint16 *) data; + + cv = find_msg_converter(ptr, msgId); + if (cv) + { + cv->freeFunc(data); + ret = TRUE; + } + else + { + ret = FALSE; + } + } + else + { + ret = FALSE; + } + + return ret; +} + +static CsrUint8 *serialize_message(CsrUint16 primType, + void *msg, + CsrSize *length, + CsrUint8 *buffer) +{ + CsrMsgConvPrimEntry *ptr; + CsrUint8 *ret; + + ptr = CsrMsgConvFind(primType); + + *length = 0; + + if (ptr) + { + const CsrMsgConvMsgEntry *cv; + + cv = find_msg_converter(ptr, *(CsrUint16 *) msg); + if (cv) + { + ret = cv->serFunc(buffer, length, msg); + } + else + { + ret = NULL; + } + } + else + { + ret = NULL; + } + + return ret; +} + +CsrSize CsrMsgConvSizeof(CsrUint16 primType, void *msg) +{ + return sizeof_message(primType, msg); +} + +CsrUint8 *CsrMsgConvSerialize(CsrUint8 *buffer, CsrSize maxBufferOffset, CsrSize *offset, CsrUint16 primType, void *msg) +{ + if (converter) + { + CsrSize serializedLength; + CsrUint8 *bufSerialized; + CsrUint8 *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(CsrUint16 primType, const CsrMsgConvMsgEntry *ce) +{ + CsrMsgConvPrimEntry *pc; + pc = CsrMsgConvFind(primType); + + if (pc) + { + /* Already registered. Do nothing */ + } + else + { + pc = CsrPmemAlloc(sizeof(*pc)); + pc->primType = primType; + pc->conv = ce; + pc->lookupFunc = NULL; + pc->next = converter->profile_converters; + converter->profile_converters = pc; + } +} +EXPORT_SYMBOL_GPL(CsrMsgConvInsert); + +CsrMsgConvMsgEntry *CsrMsgConvFindEntry(CsrUint16 primType, CsrUint16 msgType) +{ + CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); + if (ptr) + { + return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType); + } + return NULL; +} +EXPORT_SYMBOL_GPL(CsrMsgConvFindEntry); + +CsrMsgConvMsgEntry *CsrMsgConvFindEntryByMsg(CsrUint16 primType, const void *msg) +{ + CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); + if (ptr && msg) + { + CsrUint16 msgType = *((CsrUint16 *) msg); + return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType); + } + return NULL; +} + +void CsrMsgConvCustomLookupRegister(CsrUint16 primType, CsrMsgCustomLookupFunc *lookupFunc) +{ + CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); + if (ptr) + { + ptr->lookupFunc = lookupFunc; + } +} +EXPORT_SYMBOL_GPL(CsrMsgConvCustomLookupRegister); + +CsrMsgConvEntry *CsrMsgConvInit(void) +{ + if (!converter) + { + converter = (CsrMsgConvEntry *) CsrPmemAlloc(sizeof(CsrMsgConvEntry)); + + 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); + +CsrMsgConvEntry *CsrMsgConvGet(void) +{ + return converter; +} + +#ifdef ENABLE_SHUTDOWN +void CsrMsgConvDeinit(void) +{ + CsrMsgConvPrimEntry *s; + + if (converter == NULL) + { + return; + } + + /* Walk converter list and free elements. */ + s = converter->profile_converters; + while (s) + { + CsrMsgConvPrimEntry *s_next; + s_next = s->next; + CsrPmemFree(s); + s = s_next; + } + + CsrPmemFree(converter); + converter = NULL; +} +EXPORT_SYMBOL_GPL(CsrMsgConvDeinit); + +#endif /* ENABLE_SHUTDOWN */ |