| /***************************************************************************** |
| |
| (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); |