/*************************************************************************** * Copyright (c) 2012, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ***************************************************************************/ #include "nexus_pid_channel.h" #include "nexus_parser_band.h" #include "nexus_message.h" #include "nexus_memory.h" #include "bsettop_smessage.h" BDBG_MODULE(smsg); #define MAX_FILTERS 32 #define B_INVALID_PID 0xFFFF #define B_INVALID_PID_CHANNEL 0xFFFF #define B_INVALID_BAND ((int)-1) #define FILTER_SIZE 16 #define SM_MAGIC 0xBADBABE0 #define SM_WAIT (-1) #define SM_POLL_INTERVAL 50 enum sm_task_state_t { STS_NONE, STS_IDLE, STS_RUN }; struct smessage_stream { BLST_S_ENTRY(smessage_stream) next; smessage_format format; uint16_t pid; smessage_callback callback; smessage_callback overflow; void *context; void *priv; NEXUS_PidChannelHandle pidChannel; NEXUS_MessageHandle msgHandle; NEXUS_MessageStartSettings startSettings; void *buffer; size_t buffer_size; }; BLST_S_HEAD(smessage_stream_list_t, smessage_stream); struct smessage_state { uint32_t magic; int band; b_task_t task; b_mutex_t lock; enum sm_task_state_t task_state; struct smessage_stream_list_t free_filter; struct smessage_stream_list_t started_filter; struct smessage_stream sm[MAX_FILTERS]; }; static struct smessage_state sm_st; #define SM_STACK_SIZE 0x400 #define SM_PRIORITY 16 static unsigned int sm_stack[SM_STACK_SIZE]; static char * sm_task_name = "msg"; void sm_parser_task(void *param); bresult smessage_init(void *decode_cfgs) { int i; b_task_params t_param; bresult bres = b_ok; BSTD_UNUSED(decode_cfgs); BKNI_Memset(&sm_st, 0, sizeof(struct smessage_state)); BLST_S_INIT(&sm_st.free_filter); BLST_S_INIT(&sm_st.started_filter); for (i=0; iformat = format; } bos_release_mutex(&sm_st.lock); break; case smessage_format_ts: break; default: break; } return st; } /* * Summary: * Close a message stream */ void smessage_close(smessage_stream_t stream) { bresult res; res = smessage_stop(stream); if (b_ok != res) BDBG_ERR(("%s:%d", __FILE__, __LINE__)); BLST_S_INSERT_HEAD(&sm_st.free_filter, stream, next); } /* * Summary: * Initialize parameters structure */ void smessage_stream_params_init(smessage_stream_params_t *params, smessage_stream_t stream) { int i; BSTD_UNUSED(stream); if (NULL != params) { BKNI_Memset(params, 0, sizeof(smessage_stream_params_t)); params->band = B_INVALID_BAND; params->pid = B_INVALID_PID; params->pid_channel = B_INVALID_PID_CHANNEL; for (i=0; ifilter.mask[i] = 0xFF; params->filter.excl[i] = 0xFF; } } } /* * Summary: * Capture message according to the parameters */ bresult smessage_start(const smessage_stream_params_t *params, smessage_stream_t stream) { bresult res; NEXUS_ParserBandSettings parserBandSettings; NEXUS_MessageSettings settings; NEXUS_MemoryAllocationSettings memSettings; NEXUS_PidChannelSettings pidChannelSettings; BDBG_ASSERT(stream); BDBG_ASSERT(params); BDBG_ASSERT(params->buffer); if (((stream->format != smessage_format_psi) && (stream->format != smessage_format_tsc)) || (B_INVALID_BAND == params->band) || (NULL != stream->msgHandle) || (NULL != stream->pidChannel) || (0 == params->buffer_size) ) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); BDBG_ERR(("stream->msg = 0x%08x", stream->msgHandle)); BDBG_ERR(("stream->pidChannel = 0x%08x", stream->pidChannel)); BDBG_ERR(("params->pid = 0x%08x", params->pid)); BDBG_ERR(("stream->format = %d", stream->format)); BDBG_ERR(("params->band = %d", params->band)); BDBG_ERR(("params->buffer_size = %d", params->buffer_size)); goto ExitFunc; } NEXUS_Memory_GetDefaultAllocationSettings(&memSettings); res = bos_acquire_mutex(&sm_st.lock, SM_WAIT); if (res != b_ok) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); goto ExitFunc; } NEXUS_ParserBand_GetSettings((NEXUS_ParserBand)NEXUS_ParserBand_e0/*params->band*/, &parserBandSettings); parserBandSettings.sourceType = NEXUS_ParserBandSourceType_eInputBand; NEXUS_ParserBand_SetSettings((NEXUS_ParserBand)NEXUS_ParserBand_e0/*params->band*/, &parserBandSettings); stream->pid = params->pid; NEXUS_PidChannel_GetDefaultSettings(&pidChannelSettings); stream->pidChannel = NEXUS_PidChannel_Open((NEXUS_ParserBand)NEXUS_ParserBand_e0/*params->band*/, params->pid, &pidChannelSettings); if (stream->pidChannel == NULL) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); goto ExitUnlock; } NEXUS_Message_GetDefaultSettings(&settings); // settings.maxContiguousMessageSize = 4096; settings.bufferSize = 0; /* don't have Message alloc the buffer, recommended for maximum flexibility. */ stream->msgHandle = NEXUS_Message_Open(&settings); NEXUS_Message_GetDefaultStartSettings(stream->msgHandle, &stream->startSettings); memSettings.alignment = 1024; /* HW PID2BUF requires 1024 boundary */ if (NEXUS_Memory_Allocate(params->buffer_size, &memSettings, &stream->startSettings.buffer) != BERR_SUCCESS) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); NEXUS_Message_Close(stream->msgHandle); stream->msgHandle = NULL; goto ExitUnlock; } stream->buffer = params->buffer; stream->startSettings.bufferSize = params->buffer_size; switch (stream->format) { case smessage_format_tsc: stream->startSettings.format = NEXUS_MessageFormat_eTs; break; case smessage_format_psi: default: stream->startSettings.format = NEXUS_MessageFormat_ePsi; break; } stream->startSettings.psfCrcDisabled = true; /* disable CRC check on short packets */ stream->buffer_size = params->buffer_size; /* use the default filter for any data */ BKNI_Memcpy(stream->startSettings.filter.coefficient, params->filter.coef, FILTER_SIZE); BKNI_Memcpy(stream->startSettings.filter.mask, params->filter.mask, FILTER_SIZE); BKNI_Memcpy(stream->startSettings.filter.exclusion, params->filter.excl, FILTER_SIZE); stream->startSettings.pidChannel = stream->pidChannel; if (NEXUS_Message_Start(stream->msgHandle, &stream->startSettings) != NEXUS_SUCCESS) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); NEXUS_Message_Close(stream->msgHandle); stream->msgHandle = NULL; NEXUS_Memory_Free(stream->startSettings.buffer); stream->startSettings.buffer = NULL; goto ExitUnlock; } stream->callback = params->data_ready_callback; stream->overflow = params->overflow; stream->context = params->callback_context; stream->priv = params->priv; BLST_S_INSERT_HEAD(&sm_st.started_filter, stream, next); res = b_ok; ExitUnlock: bos_release_mutex(&sm_st.lock); ExitFunc: return res; } bresult smessage_stop(smessage_stream_t stream) { bresult res; BDBG_ASSERT(stream); res = bos_acquire_mutex(&sm_st.lock, SM_WAIT); if (res != b_ok) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); goto ExitFunc; } if (stream->msgHandle == NULL) { /* already closed */ bos_release_mutex(&sm_st.lock); return b_ok; } if (stream->msgHandle) { NEXUS_Message_Stop(stream->msgHandle); NEXUS_Message_Close(stream->msgHandle); stream->msgHandle = NULL; } if (stream->pidChannel != NULL) { NEXUS_PidChannel_Close(stream->pidChannel); stream->pidChannel = NULL; } if (stream->startSettings.buffer) { NEXUS_Memory_Free(stream->startSettings.buffer); stream->startSettings.buffer = NULL; } BLST_S_REMOVE(&sm_st.started_filter, stream, smessage_stream, next); res = b_ok; bos_release_mutex(&sm_st.lock); ExitFunc: return res; } bresult smessage_get_buffer(smessage_stream_t stream, const void ** pbuffer, size_t * plength) { bresult res; res = bos_acquire_mutex(&sm_st.lock, SM_WAIT); if (res != b_ok) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); goto ExitFunc; } if (NEXUS_Message_GetBuffer(stream->msgHandle, (const void **)pbuffer, plength) != NEXUS_SUCCESS) { res = -1; } bos_release_mutex(&sm_st.lock); ExitFunc: return res; } bresult smessage_read_complete(smessage_stream_t stream, size_t consumed) { bresult res; res = bos_acquire_mutex(&sm_st.lock, SM_WAIT); if (res != b_ok) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); goto ExitFunc; } NEXUS_Message_ReadComplete(stream->msgHandle, consumed); bos_release_mutex(&sm_st.lock); ExitFunc: return res; } void sm_parser_task(void *param) { smessage_stream_t stream; bresult res; void *buffer; size_t size; BSTD_UNUSED(param); while(1) { res = bos_acquire_mutex(&sm_st.lock, SM_WAIT); if (res == b_ok) { for (stream = BLST_S_FIRST(&sm_st.started_filter); stream; stream = BLST_S_NEXT(stream, next)) { if (!stream->callback || !stream->buffer) continue; size = 0; if (NEXUS_Message_GetBuffer(stream->msgHandle, (const void **)&buffer, &size) == NEXUS_SUCCESS) { if (size <= 0) continue; BKNI_Memcpy(stream->buffer, buffer, size); /* use the app-allocated buffer. */ stream->buffer = stream->callback(stream->context, size); NEXUS_Message_ReadComplete(stream->msgHandle, size); if (stream->buffer == NULL) { bos_release_mutex(&sm_st.lock); smessage_stop(stream); if (bos_acquire_mutex(&sm_st.lock, SM_WAIT) != b_ok) { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); break; } } } } res = bos_release_mutex(&sm_st.lock); if (b_ok != res) { BDBG_ERR(("bos_release_mutex failed! exiting ...")); break; } } else { BDBG_ERR(("%s:%d", __FILE__, __LINE__)); } bos_sleep(SM_POLL_INTERVAL); } }