blob: a18a9b4ea9bb6ddc753573b9f5520aa78d67f6e4 [file] [log] [blame]
/****************************************************************************
Copyright 2009 - 2011 Broadcom Corporation
Unless you and Broadcom execute a separate written software license agreement
governing use of this software, this software is licensed to you under the
terms of the GNU General Public License version 2 (the GPL), available at
http://www.broadcom.com/licenses/GPLv2.php
with the following added to such license:
As a special exception, the copyright holders of this software give you
permission to link this software with independent modules, and to copy and
distribute the resulting executable under terms of your choice, provided
that you also meet, for each linked independent module, the terms and
conditions of the license of that module.
An independent module is a module which is not derived from this software.
The special exception does not apply to any modifications of the software.
Notwithstanding the above, under no circumstances may you combine this software
in any way with any other Broadcom software provided under a license other than
the GPL, without Broadcom's express prior written consent.
***************************************************************************/
/**
*
* @file audio_vdriver_audlog.c
*
* @brief
*
****************************************************************************/
#include <linux/module.h>
#include "mobcom_types.h"
#include "resultcode.h"
#include "msconsts.h"
#include "audio_consts.h"
#include "bcm_fuse_sysparm_CIB.h"
#include "audio_ddriver.h"
#include "csl_caph.h"
#include "audio_vdriver.h"
#include "csl_aud_queue.h"
#include "auddrv_audlog.h"
#include "audio_controller.h"
#include "log_sig_code.h"
#include "csl_log.h"
#include "bcmlog.h"
#include "audio_caph.h"
#include "caph_common.h"
#include "audio_trace.h"
/**
*
* @addtogroup AudioDriverGroup
* @{
*/
/* local defines */
/* #define DBG_MSG_TO_FILE */
#undef DBG_MSG_TO_FILE
#if defined(CONFIG_BCM_MODEM)
#define AUDIO_MODEM(a) a
#else
#define AUDIO_MODEM(a)
#endif
/* local structures */
static UInt16 audio_log_inited;
wait_queue_head_t bcmlogreadq;
wait_queue_head_t bcmlogwriteq;
void *bcmlog_stream_ptr;
int *bcmlog_stream_area;
enum {
AUDDRV_LOG_STATE_UNDEFEIND,
AUDDRV_LOG_STATE_INITED,
AUDDRV_LOG_STATE_STARTED,
AUDDRV_LOG_STATE_CLOSED
} AUDDRV_LOG_STATE_en_t;
/* local variables */
static AUDLOG_INFO sLogInfo;
static UInt16 auddrv_log_state = AUDDRV_LOG_STATE_CLOSED;
static int sAudioLogTaskReadyFlag;
UInt8 *loggingbuf;
/* APIs */
/* Initialize driver internal variables and task queue only needed to
* save to flash file. */
Result_t AUDDRV_AudLog_Init(void)
{
Int16 n;
if (((sLogInfo.log_consumer[0] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[0] < 0x8000) ||
(sLogInfo.log_consumer[1] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[1] < 0x8000) ||
(sLogInfo.log_consumer[2] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[2] < 0x8000) ||
(sLogInfo.log_consumer[3] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[3] < 0x8000)) &&
audio_log_inited == 0) {
/* This is for FFS option, create buffer in heap, copy data from
shared memory to it and mmap to user space, reserve memory with
kmalloc - Allocating Memory in the Kernel. Max we need
LOG_FRAME_SIZE*4, PAGESIZE+(LOG_FRAME_SIZE*4) because
kmalloc_area should fall within PAGE BOUNDRY */
bcmlog_stream_ptr = NULL;
/* 4k+1024 , page_size is linux page size , 4K by default */
bcmlog_stream_ptr = kmalloc(PAGE_SIZE +
((sizeof(LOG_FRAME_t)) * 4), GFP_KERNEL);
if (bcmlog_stream_ptr == NULL) {
aError("kmalloc failed\n");
return -1;
}
/* Make sure page boundry */
bcmlog_stream_area =
(int *)(((unsigned long)bcmlog_stream_ptr + PAGE_SIZE - 1) &
PAGE_MASK);
if (bcmlog_stream_area == NULL) {
aError("Couldn't get proper page boundry, ");
aError("may be issue for"
"page swapping to user space\n");
return -1;
}
/*pr_alert( "Setup bcmlog_stream_area = %x\n",
bcmlog_stream_area);*/
for (n = 0; n < (2 * PAGE_SIZE); n += PAGE_SIZE) {
/* reserve all pages to make them remapable */
SetPageReserved(virt_to_page
(((unsigned long)bcmlog_stream_area) +
n));
}
}
audio_log_inited = 1;
if (auddrv_log_state != AUDDRV_LOG_STATE_INITED
&& auddrv_log_state != AUDDRV_LOG_STATE_STARTED) {
auddrv_log_state = AUDDRV_LOG_STATE_INITED;
/* aTrace(LOG_AUDIO_DRIVER, "AUDDRV_AudLog_Init"); */
}
return 0;
}
/* ISR to handle STATUS_AUDIO_STREAM_DATA_READY from DSP called from AP
AP_Audio_ISR_Handler (status = STATUS_AUDIO_STREAM_DATA_READY) */
void AUDLOG_ProcessLogChannel(UInt16 audio_stream_buffer_idx)
{
int n;
UInt16 size = 0; /* number of 16-bit words */
UInt16 stream; /* the stream number: 1, 2, 3, 4 */
UInt16 sender = 0; /* the capture point */
int write_msg;
write_msg = 1;
for (n = 0; n < LOG_STREAM_NUMBER; n++) {
stream = n + 1;
if (sLogInfo.log_capture_point[n] >= 0x8000) {
if (write_msg) {
write_msg = 0;
audio_data_gone = stream;
logpoint_buffer_idx = audio_stream_buffer_idx;
wake_up_interruptible(&bcmlogwriteq);
}
} else {
if (loggingbuf != NULL) {
AUDIO_MODEM(size =
CSL_LOG_Read(stream,
audio_stream_buffer_idx,
(UInt8 *) loggingbuf,
&sender);)
}
/* check the SHmem ctrl point. */
if (sender != 0) {
if (sLogInfo.log_consumer[n] == LOG_TO_PC) {
/*aTrace(LOG_AUDIO_DRIVER, "AUDLOG: 0x%x
addr=0x%p size=%ld stream=%d sender=%d",
DSP_DATA, loggingbuf, size, stream, sender);*/
if (loggingbuf) {
/* send binary data to
log port. The size is
number of bytes (for MTT). */
BCMLOG_LogSignal(DSP_DATA,
(UInt16 *)loggingbuf,
size, stream, sender);
} else {
aError(
"!!!!!! Err ptr = 0x%p size=%d ",
loggingbuf, size);
aError(
"stream=%d sender=%d\n",
stream, sender);
}
} else if (bcmlog_stream_ptr != NULL) {
/* copy 81 bytes of data */
/*
memcpy(log_cb_info_ks_ptr[n].log_msg,
(UInt16 *)loggingbuf, size/2);
log_cb_info_ks_ptr[n].log_capture_control = sender;
log_cb_info_ks_ptr[n].stream_index = stream; */
}
}
}
}
if ((sLogInfo.log_consumer[0] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[0] < 0x8000) ||
(sLogInfo.log_consumer[1] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[1] < 0x8000) ||
(sLogInfo.log_consumer[2] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[2] < 0x8000) ||
(sLogInfo.log_consumer[3] == LOG_TO_FLASH &&
sLogInfo.log_capture_point[3] < 0x8000)) {
if (bcmlog_stream_ptr != NULL) {
/* Wakeup read in user space to go ahead and do mmap
buffer read */
audio_data_arrived = 1;
wake_up_interruptible(&bcmlogreadq);
}
}
/*aTrace(LOG_AUDIO_DRIVER,
"<=== process_Log_Channel done <===\r\n");*/
}
/* clean up audio log task and queue */
Result_t AUDDRV_AudLog_Shutdown(void)
{
UInt16 *local_bcmlogptr = bcmlog_stream_ptr;
/* Use local pointer to free so it wouldnt disturb ISR activities */
bcmlog_stream_ptr = NULL;
/* pr_alert( "AUDDRV_AudLog_Shutdown\n"); */
if (sLogInfo.log_consumer[0] == LOG_TO_FLASH
|| sLogInfo.log_consumer[1] == LOG_TO_FLASH
|| sLogInfo.log_consumer[2] == LOG_TO_FLASH
|| sLogInfo.log_consumer[3] == LOG_TO_FLASH) {
if (local_bcmlogptr != NULL)
kfree(local_bcmlogptr);
}
/* flag to stop writting logging message */
sAudioLogTaskReadyFlag = 0; /* enable task */
auddrv_log_state = AUDDRV_LOG_STATE_CLOSED;
audio_log_inited = 0;
return 0;
}
/**
*
* Function Name: AUDDRV_AudLog_Start
*
* Description: Start the audio logging (at*maudlog=1,stream,channel cmd)
* Driver sets up shared memory control
* Notes:
*
******************************************************************************/
Result_t AUDDRV_AudLog_Start(UInt32 log_stream,
UInt32 log_capture_point,
AUDLOG_DEST_en_t log_consumer, char *filename)
{
Result_t res = RESULT_OK;
if ((log_stream >= 0x10) && (log_stream < 0x20)) {
aTrace(LOG_AUDIO_DRIVER,
"=> Start Music Playback Log @stream %ld log_consumer %d=>\r\n",
log_stream, (uint) log_consumer);
return res;
} else if (log_stream > 0 && log_stream <= 4) {
/* check the capture point number is in reasonable range */
#if 0
if ((log_capture_point <= 0) || (log_capture_point > 0x8000))
return RESULT_ERROR;
#endif
/* set up logging message consumer */
sLogInfo.log_consumer[log_stream - 1] = log_consumer;
sLogInfo.log_capture_point[log_stream - 1] = log_capture_point;
/* call init to check if need to open file and create task */
AUDDRV_AudLog_Init();
auddrv_log_state = AUDDRV_LOG_STATE_STARTED;
/* check the stream number is between 1 and 4 */
/* start the stream logging captrue */
/* allocate memory for all the 4 streams as we read all the
* 4 streams data in the AUDLOG_ProcessLogChannel() */
loggingbuf = kmalloc(LOG_WB_SIZE, GFP_KERNEL); /*maxFrameSize*/
if (loggingbuf == NULL) {
aError("AUDDRV_AudLog_Start : not able to allocate");
aError("memory for the logging data\n");
return RESULT_LOW_MEMORY;
}
AUDIO_MODEM(res = CSL_LOG_Start(log_stream, log_capture_point);)
aTrace(LOG_AUDIO_DRIVER,
"===> Start_Log stream %ld log_consumer %d===>\r\n",
log_stream, (uint) log_consumer);
}
return res;
}
/**
*
* Function Name: AUDDRV_AudLog_Stop
*
* Description: Stop the audio logging (at*maudlog=2 cmd)
*
* Notes:
*
******************************************************************************/
Result_t AUDDRV_AudLog_Stop(UInt32 log_stream)
{
Result_t res = RESULT_OK;
UInt8 flag = 0;
aTrace(LOG_AUDIO_DRIVER, "<=== Stop_Log stream %ld <===",
log_stream);
AUDIO_MODEM(res = CSL_LOG_Stop((UInt16) log_stream, &flag);)
aTrace(LOG_AUDIO_DRIVER,
"<=== Stop_Log stream done %ld <===, flag %d",
log_stream, flag);
if (flag == 1) {
if (loggingbuf != NULL)
kfree(loggingbuf);
AUDDRV_AudLog_Shutdown();
}
return res;
}