blob: 9168ae2f28b084a54f6e5761305535f1cc666e43 [file] [log] [blame]
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*****************************************************************************
Copyright 2010-2011 Broadcom Corporation. All rights reserved.
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, available at
http://www.gnu.org/copyleft/gpl.html (the "GPL").
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.
*****************************************************************************/
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <sound/hwdep.h>
#include "mobcom_types.h"
#include "osdal_os.h"
#include "resultcode.h"
#include "audio_consts.h"
#include "audio_trace.h"
#include "bcm_fuse_sysparm_CIB.h"
#include "csl_caph.h"
#include "audio_vdriver.h"
#include "audio_controller.h"
#include "audio_ddriver.h"
#include "audio_caph.h"
#include "caph_common.h"
#include "csl_voip.h"
#include "csl_dsp.h"
#include "osdw_dsp_drv.h"
#include "csl_audio_render.h"
#include "bcm_audio.h"
#include "auddrv_audlog.h"
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/broadcom/bcm_major.h>
#include <caph_common.h>
/* Local defines */
#define VOIP_FRAMES_IN_BUFFER 1
enum __voip_hwdep_status_t {
voip_hwdep_status_none,
voip_hwdep_status_opened,
voip_hwdep_status_started,
voip_hwdep_status_stopped,
voip_hwdep_status_released,
};
struct __dl_frame {
u32 timestamp;
char data[VOIP_MAX_FRAME_LEN];
};
struct __audio_voip_driver {
u32 voip_data_dl_rd_index;
u32 voip_data_dl_wr_index;
u32 voip_data_ul_rd_index;
u32 voip_data_ul_wr_index;
u8 *voip_data_ul_buf_ptr;
u8 *voip_data_dl_buf_ptr;
u32 dl_timestamp;
AUDIO_DRIVER_HANDLE_t drv_handle;
};
#define audio_voip_driver_t struct __audio_voip_driver
struct __bcm_caph_hwdep_voip {
int status;
int frames_available_to_read;
int frames_available_to_write;
int writecount;
wait_queue_head_t sleep;
audio_voip_driver_t *buffer_handle;
AUDIO_SOURCE_Enum_t mic;
AUDIO_SINK_Enum_t spk;
u32 codec_type_ul;
u32 codec_type_dl;
u8 voip_type;
u32 frame_size_ul;
u32 frame_size_dl;
u32 buffer_size_ul;
u32 buffer_size_dl;
int dlstarted;
int ulstarted;
};
#define bcm_caph_hwdep_voip_t struct __bcm_caph_hwdep_voip
static const u16 svoipframelen[] = { 320, 158, 36, 164, 640, 68 };
static u16 svoipamrsilenceframe[1] = { 0x000f };
static u32 voipinstcnt;
static Boolean isvolte = FALSE;
bcm_caph_voip_log_t voip_log;
/* local functions */
static void HWDEP_VOIP_DumpUL_CB(void *pPrivate, u8 * pSrc, u32 nSize);
static void HWDEP_VOIP_FillDL_CB(
void *pPrivate,
u8 *pDst,
u32 nSize,
u32 *timestamp);
static void FillSilenceFrame(u32 codec_type, u32 frame_size, u8 *pDst);
static void voip_log_capture(CAPTURE_POINT_t log_pint, unsigned char *buf,
int size);
uint32_t guULCount = 0, guDLCount = 0;
static void FillSilenceFrame(u32 codec_type, u32 frame_size, u8 *pDst)
{
CSL_VOIP_Buffer_t tmpBuf;
memset(&tmpBuf, 0, sizeof(CSL_VOIP_Buffer_t));
if (codec_type == VoIP_Codec_AMR475)
tmpBuf.voip_frame.frame_amr[0] = svoipamrsilenceframe[0];
else if (codec_type == VOIP_Codec_AMR_WB_7K)
tmpBuf.voip_frame.frame_amr_wb.frame_type = 0x7;
else if (codec_type == VoIP_Codec_FR) {
tmpBuf.voip_frame.frame_fr[0] = 1;
tmpBuf.voip_frame.frame_fr[1] = 0;
tmpBuf.voip_frame.frame_fr[2] = 0;
} else if (codec_type == VOIP_Codec_G711_U) {
tmpBuf.voip_frame.frame_g711[0].frame_type = 1;
tmpBuf.voip_frame.frame_g711[1].frame_type = 1;
}
memcpy(pDst, &(tmpBuf.voip_frame), frame_size);
}
static void HWDEP_VOIP_DumpUL_CB(void *pPrivate, u8 * pSrc, u32 nSize)
{
bcm_caph_hwdep_voip_t *pVoIP;
pVoIP = (bcm_caph_hwdep_voip_t *) pPrivate;
/* DEBUG("HWDEP_VOIP_DumpUL_CB nSize %d pVoIP 0x%x\n",
* nSize,pVoIP);
*/
guULCount++;
if (0 == (guULCount%500))
aTrace(LOG_ALSA_INTERFACE, "DumpUL_CB ulstarted");
/*aTrace(LOG_ALSA_INTERFACE, "DumpUL_CB ulstarted=%d dlstarted="
"%d, voipinstcnt=%d frames_available_to_read=%d, "
"frames_available_to_write=%d",
pVoIP->ulstarted, pVoIP->dlstarted, voipinstcnt,
pVoIP->frames_available_to_read,
pVoIP->frames_available_to_write); */
if (pVoIP->ulstarted == 0)
return;
if (pVoIP->buffer_handle) {
if (pVoIP->buffer_handle->voip_data_ul_buf_ptr) {
memcpy(pVoIP->buffer_handle->voip_data_ul_buf_ptr +
pVoIP->buffer_handle->voip_data_ul_wr_index,
pSrc, nSize);
pVoIP->frames_available_to_read++;
if (pVoIP->frames_available_to_read > 1)
aTrace(LOG_ALSA_INTERFACE, "more than 1 frame");
/*aTrace(LOG_ALSA_INTERFACE, "more than 1 frame"
" available frame_size %d, readcount %d\n",
pVoIP->frame_size_ul,
pVoIP->frames_available_to_read);*/
#ifdef CONFIG_VOIP_BUFFER_INCREASE
pVoIP->buffer_handle->voip_data_ul_wr_index += nSize;
if (pVoIP->buffer_handle->voip_data_ul_wr_index >=
pVoIP->buffer_size_ul) {
pVoIP->buffer_handle->voip_data_ul_wr_index -=
pVoIP->buffer_size_ul;
}
#endif
}
}
wake_up(&pVoIP->sleep);
}
static void HWDEP_VOIP_FillDL_CB(
void *pPrivate,
u8 *pDst,
u32 nSize,
u32 *timestamp)
{
bcm_caph_hwdep_voip_t *pVoIP;
pVoIP = (bcm_caph_hwdep_voip_t *) pPrivate;
guDLCount++;
if (0 == (guDLCount%500))
/*aTrace(LOG_ALSA_INTERFACE, "FillDL_CB ulstarted=%d
dlstarted="
"%d, voipinstcnt=%d frames_available_to_read=%d, "
"frames_available_to_write=%d",
pVoIP->ulstarted, pVoIP->dlstarted, voipinstcnt,
pVoIP->frames_available_to_read,
pVoIP->frames_available_to_write);*/
if (pVoIP->dlstarted == 0) {
FillSilenceFrame(pVoIP->codec_type_dl, nSize, pDst);
return;
}
if (pVoIP->buffer_handle->voip_data_dl_buf_ptr) {
/*DEBUG("HWDEP_VOIP_FillDL_CB pVoIP->"
*"frames_available_to_write %d\n", pVoIP->
* frames_available_to_write);
*/
if (pVoIP->frames_available_to_write == 0) {
/* fill with silent data based on the frame type */
FillSilenceFrame(pVoIP->codec_type_dl, nSize, pDst);
/*aTrace(LOG_ALSA_INTERFACE, "under run frame_size %d,"
"writecount %d\n",
pVoIP->frame_size_dl, pVoIP->writecount);*/
} else {
if (isvolte)
*timestamp = pVoIP->buffer_handle->dl_timestamp;
else
*timestamp = 0;
memcpy(pDst,
pVoIP->buffer_handle->voip_data_dl_buf_ptr +
pVoIP->buffer_handle->voip_data_dl_rd_index,
nSize);
pVoIP->frames_available_to_write--;
if (!isvolte)
pVoIP->writecount++;
#ifdef CONFIG_VOIP_BUFFER_INCREASE
pVoIP->buffer_handle->voip_data_dl_rd_index += nSize;
if (pVoIP->buffer_handle->voip_data_dl_rd_index >=
pVoIP->buffer_size_dl) {
pVoIP->buffer_handle->voip_data_dl_rd_index -=
pVoIP->buffer_size_dl;
}
#endif
}
}
wake_up(&pVoIP->sleep);
}
#if 1
static int voip_open(struct inode *voipinode , struct file *filp)
{
voipdev *pvoipchrdevpvtdata;
aTrace(LOG_ALSA_INTERFACE, "voip_open\n");
pvoipchrdevpvtdata =
container_of(voipinode->i_cdev, voipdev, voipcdev);
filp->private_data = pvoipchrdevpvtdata;
aTrace(LOG_ALSA_INTERFACE, "filp->private_data = 0x%x, filp = 0x%x\n",
(unsigned int)filp->private_data, (unsigned int)filp);
return 0;
}
static int voip_release(struct inode *voipinode , struct file *filp)
{
voipdev *pvoipchrdevpvtdata = (voipdev *)filp->private_data;
bcm_caph_hwdep_voip_t *pvoip = pvoipchrdevpvtdata->pvoip;
aTrace(LOG_ALSA_INTERFACE , "voip_release\n");
if (voipinstcnt == 0 && pvoip != NULL) {
kfree(pvoip);
pvoipchrdevpvtdata->pvoip = NULL;
aError("freeing pvoip\n");
}
return 0;
}
static ssize_t voip_read(struct file *filep, char __user *buf,
size_t count, loff_t *pos)
{
bcm_caph_hwdep_voip_t *pvoip;
voipdev *voipchrdevpvtdata;
long ret = 0;
voipchrdevpvtdata = (voipdev *)filep->private_data;
pvoip = (bcm_caph_hwdep_voip_t *)voipchrdevpvtdata->pvoip;
if (!pvoip) {
aError("!pvoip return 0");
return 0;
}
/* DEBUG("voip_read count %ld\n",count); */
if ((pvoip->status == voip_hwdep_status_started)
&& (pvoip->frames_available_to_read > 0)) {
if (pvoip->frames_available_to_read) {
if (pvoip->buffer_handle->voip_data_ul_buf_ptr) {
ret =
copy_to_user(buf,
pvoip->buffer_handle->
voip_data_ul_buf_ptr +
pvoip->buffer_handle->
voip_data_ul_rd_index,
pvoip->frame_size_ul);
voip_log_capture(AUD_LOG_VOCODER_UL,
pvoip->buffer_handle->
voip_data_ul_buf_ptr +
pvoip->buffer_handle->
voip_data_ul_rd_index,
pvoip->frame_size_ul);
pvoip->frames_available_to_read--;
#ifdef CONFIG_VOIP_BUFFER_INCREASE
pvoip->buffer_handle->voip_data_ul_rd_index +=
pvoip->frame_size_ul;
if (pvoip->buffer_handle->
voip_data_ul_rd_index >=
pvoip->buffer_size_ul) {
pvoip->buffer_handle->
voip_data_ul_rd_index -=
pvoip->buffer_size_ul;
}
#endif
ret = pvoip->frame_size_ul;
}
}
} else
ret = 0;
return ret;
}
static ssize_t voip_write(struct file *filep, const char __user *buf,
size_t count, loff_t *pos)
{
bcm_caph_hwdep_voip_t *pvoip;
voipdev *voipchrdevpvtdata;
long ret = 0;
struct __dl_frame *frame_dl_data = (struct __dl_frame *)buf;
voipchrdevpvtdata = (voipdev *)filep->private_data;
pvoip = (bcm_caph_hwdep_voip_t *)voipchrdevpvtdata->pvoip;
if (!pvoip) {
aError("voip_write returns error as !pvoip");
return count;
}
/* DEBUG("voip_write pvoip->frame_size %d,pvoip->"
* "writecount %d\n",pvoip->frame_size,pvoip->writecount);
*/
if ((pvoip->status == voip_hwdep_status_started)
&& (pvoip->buffer_handle)) {
if (pvoip->buffer_handle->voip_data_dl_buf_ptr) {
if (isvolte) {
pvoip->buffer_handle->dl_timestamp =
frame_dl_data->timestamp;
ret =
copy_from_user(
pvoip->buffer_handle->
voip_data_dl_buf_ptr +
pvoip->buffer_handle->
voip_data_dl_wr_index,
(struct __dl_frame *)
frame_dl_data->data,
pvoip->frame_size_dl);
voip_log_capture(AUD_LOG_VOCODER_DL,
pvoip->buffer_handle->
voip_data_dl_buf_ptr +
pvoip->buffer_handle->
voip_data_dl_wr_index,
pvoip->frame_size_dl);
/* send the DL frame to DSP . In case of VoLTE,
whenever the application sends the data,
need to send it to DSP.No need to wait
for DSP callback. */
VOLTE_ProcessDLData();
} else {
ret =
copy_from_user(pvoip->buffer_handle->
voip_data_dl_buf_ptr +
pvoip->buffer_handle->
voip_data_dl_wr_index,
buf,
pvoip->frame_size_dl);
voip_log_capture(AUD_LOG_VOCODER_DL,
pvoip->buffer_handle->
voip_data_dl_buf_ptr +
pvoip->buffer_handle->
voip_data_dl_wr_index,
pvoip->frame_size_dl);
}
pvoip->frames_available_to_write++;
if (!isvolte)
pvoip->writecount--;
#ifdef CONFIG_VOIP_BUFFER_INCREASE
pvoip->buffer_handle->voip_data_dl_wr_index +=
pvoip->frame_size_dl;
if (pvoip->buffer_handle->voip_data_dl_wr_index >=
pvoip->buffer_size_dl) {
pvoip->buffer_handle->voip_data_dl_wr_index -=
pvoip->buffer_size_dl;
}
#endif
}
ret = pvoip->frame_size_dl;
} else
ret = 0;
return ret;
}
static long voip_ioctl(struct file *hw, unsigned int cmd, unsigned long arg)
{
bcm_caph_hwdep_voip_t *pvoip;
voipdev *pvoipchrdevpvtdata;
long ret = 0;
Boolean enable = FALSE;
Int32 size = 0;
int data;
voip_codec_type_data_t val;
static UserCtrl_data_t *dataptr;
brcm_alsa_chip_t *pchip = NULL;
struct treq_sysparm_t *eq;
struct snd_card *pcard = NULL;
pvoipchrdevpvtdata = (voipdev *)hw->private_data;
pvoip = (bcm_caph_hwdep_voip_t *)pvoipchrdevpvtdata->pvoip;
pcard = (struct snd_card *)pvoipchrdevpvtdata->card;
pchip = (brcm_alsa_chip_t *)pcard->private_data;
/*aTrace(LOG_ALSA_INTERFACE, "ALSA-CAPH
hwdep_ioctl cmd=%08X\n", cmd);*/
switch (cmd) {
case VoIP_Ioctl_GetVersion:
/* ret = put_user(BrcmAACEncVersion, (int __user *)arg); */
break;
case VoIP_Ioctl_Start:
aTrace(LOG_ALSA_INTERFACE, "m:inside ioctl start\n");
get_user(data, (int __user *)arg);
if (voipinstcnt == 0) { /* start VoIP only once */
BRCM_AUDIO_Param_RateChange_t param_rate_change;
BRCM_AUDIO_Param_Open_t param_open;
BRCM_AUDIO_Param_Prepare_t parm_prepare;
BRCM_AUDIO_Param_Start_t param_start;
voipinstcnt++;
#if 0
hw->private_data =
kzalloc(sizeof(bcm_caph_hwdep_voip_t), GFP_KERNEL);
CAPH_ASSERT(hw->private_data);
pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;
#endif
pvoipchrdevpvtdata->pvoip =
kzalloc(sizeof(bcm_caph_hwdep_voip_t), GFP_KERNEL);
pvoip = pvoipchrdevpvtdata->pvoip;
CAPH_ASSERT(pvoip);
init_waitqueue_head(&pvoip->sleep);
pvoip->buffer_handle =
(audio_voip_driver_t *)
kzalloc(sizeof(audio_voip_driver_t), GFP_KERNEL);
if (pvoip->buffer_handle)
memset((u8 *) pvoip->buffer_handle, 0,
sizeof(audio_voip_driver_t));
else {
pvoip->buffer_handle = NULL;
return -ENOMEM;
}
/*ul data*/
pvoip->codec_type_ul = pchip->voip_data.codec_type_ul;
pvoip->frame_size_ul = svoipframelen[pvoip->
codec_type_ul];
pvoip->buffer_size_ul = pvoip->frame_size_ul *
VOIP_FRAMES_IN_BUFFER;
pvoip->buffer_handle->voip_data_ul_buf_ptr =
kzalloc(pvoip->buffer_size_ul, GFP_KERNEL);
if (pvoip->buffer_handle->voip_data_ul_buf_ptr)
memset(pvoip->buffer_handle->
voip_data_ul_buf_ptr, 0,
pvoip->buffer_size_ul);
else {
if (pvoip->buffer_handle->
voip_data_dl_buf_ptr) {
kfree(pvoip->buffer_handle->
voip_data_dl_buf_ptr);
pvoip->buffer_handle->
voip_data_dl_buf_ptr = NULL;
}
pvoip->buffer_handle->voip_data_ul_buf_ptr =
NULL;
kfree(pvoip->buffer_handle);
pvoip->buffer_handle = NULL;
return -ENOMEM;
}
/*dl data*/
pvoip->codec_type_dl = pchip->voip_data.codec_type_dl;
pvoip->frame_size_dl = svoipframelen[pvoip->
codec_type_dl];
pvoip->buffer_size_dl = pvoip->frame_size_dl *
VOIP_FRAMES_IN_BUFFER;
pvoip->buffer_handle->voip_data_dl_buf_ptr =
kzalloc(pvoip->buffer_size_dl, GFP_KERNEL);
if (pvoip->buffer_handle->voip_data_dl_buf_ptr) {
memset(pvoip->buffer_handle->
voip_data_dl_buf_ptr, 0,
pvoip->buffer_size_dl);
} else {
if (pvoip->buffer_handle->
voip_data_ul_buf_ptr) {
kfree(pvoip->buffer_handle->
voip_data_ul_buf_ptr);
pvoip->buffer_handle->
voip_data_ul_buf_ptr = NULL;
}
pvoip->buffer_handle->voip_data_dl_buf_ptr =
NULL;
kfree(pvoip->buffer_handle);
pvoip->buffer_handle = NULL;
return -ENOMEM;
}
param_open.drv_handle = NULL;
param_open.drv_type = AUDIO_DRIVER_VOIP;
AUDIO_Ctrl_Trigger(ACTION_AUD_OpenVoIP,
&param_open, NULL, 1);
pvoip->buffer_handle->drv_handle =
param_open.drv_handle;
if (!pvoip->buffer_handle->drv_handle) {
kfree(pvoip->buffer_handle->
voip_data_dl_buf_ptr);
pvoip->buffer_handle->
voip_data_dl_buf_ptr = NULL;
kfree(pvoip->buffer_handle->
voip_data_ul_buf_ptr);
pvoip->buffer_handle->
voip_data_ul_buf_ptr = NULL;
kfree(pvoip->buffer_handle);
pvoip->buffer_handle = NULL;
aError("voip_ioctl failed with ENOMEM 4");
return -ENOMEM;
}
/* set UL callback */
parm_prepare.drv_handle =
pvoip->buffer_handle->drv_handle;
parm_prepare.cbParams.voipULCallback =
HWDEP_VOIP_DumpUL_CB;
parm_prepare.cbParams.pPrivateData = (void *)pvoip;
AUDIO_Ctrl_Trigger(
ACTION_AUD_SET_VOIP_UL_CB,
&parm_prepare, NULL, 0);
/* set DL callback */
parm_prepare.drv_handle =
pvoip->buffer_handle->drv_handle;
parm_prepare.cbParams.voipDLCallback =
HWDEP_VOIP_FillDL_CB;
parm_prepare.cbParams.pPrivateData = (void *)pvoip;
AUDIO_Ctrl_Trigger(
ACTION_AUD_SET_VOIP_DL_CB,
&parm_prepare, NULL, 0);
/* VoIP is always 16K.
No need to set the codec type here*/
if (isvolte) {
if (((data == VoIP_UL) &&
((pvoip->codec_type_ul == 4) ||
(pvoip->codec_type_ul == 5)))
|| ((data == VoIP_DL) &&
((pvoip->codec_type_dl == 4) ||
(pvoip->codec_type_dl == 5)))) {
/* VOIP_PCM_16K or
VOIP_AMR_WB_MODE_7k */
param_rate_change.codecID = 0x0A;
} else
param_rate_change.codecID = 0x06;
AUDIO_Ctrl_Trigger(ACTION_AUD_RateChange,
&param_rate_change, NULL, 0);
}
param_start.drv_handle =
pvoip->buffer_handle->drv_handle;
param_start.data = (void *)&pchip->voip_data;
AUDIO_Ctrl_Trigger(ACTION_AUD_StartVoIP,
&param_start, NULL, 0);
pvoip->writecount = VOIP_FRAMES_IN_BUFFER;
pvoip->status = voip_hwdep_status_started;
aError("Status made to voip_hwdep_status_started");
} else {
voipinstcnt++;
/*Limit Voip instance to two*/
if (voipinstcnt > 2)
voipinstcnt = 2;
aTrace(LOG_ALSA_INTERFACE,
"VoIP_Ioctl_Start -> just increment "
"the count, voip already started\n");
}
if (pvoip != NULL) {
if (data == VoIP_UL)
pvoip->ulstarted = 1;
else
pvoip->dlstarted = 1;
}
break;
case VoIP_Ioctl_Stop:
get_user(data, (int __user *)arg);
/*aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Stop type=%d (2==UL) "
"voipinstcnt=%u\n", data, voipinstcnt);*/
if (data == VoIP_UL)
pvoip->ulstarted = 0;
else
pvoip->dlstarted = 0;
if (voipinstcnt == 2)
voipinstcnt--;
else if ((voipinstcnt == 1) ||
(pvoip->ulstarted == 0 &&
pvoip->dlstarted == 0)) {
BRCM_AUDIO_Param_Stop_t param_stop;
BRCM_AUDIO_Param_Close_t param_close;
param_stop.drv_handle =
pvoip->buffer_handle->drv_handle;
AUDIO_Ctrl_Trigger(ACTION_AUD_StopVoIP,
&param_stop, NULL, 0);
param_close.drv_handle =
pvoip->buffer_handle->drv_handle;
AUDIO_Ctrl_Trigger(ACTION_AUD_CloseVoIP,
&param_close, NULL, 1);
kfree(pvoip->buffer_handle->voip_data_dl_buf_ptr);
pvoip->buffer_handle->voip_data_dl_buf_ptr = NULL;
kfree(pvoip->buffer_handle->voip_data_ul_buf_ptr);
pvoip->buffer_handle->voip_data_ul_buf_ptr = NULL;
kfree(pvoip->buffer_handle);
pvoip->buffer_handle = NULL;
pvoip->status = voip_hwdep_status_stopped;
wake_up(&pvoip->sleep);
voipinstcnt = 0;
}
break;
case VoIP_Ioctl_SetSource:
aTrace(LOG_ALSA_INTERFACE ,
" Warning: VoIP_Ioctl_SetSource"
"is depreciated , please"
"use mixer control VC-SEL instead\n");
break;
case VoIP_Ioctl_SetSink:
aTrace(LOG_ALSA_INTERFACE ,
" Warning: VoIP_Ioctl_SetSink"
"is depreciated, please"
"use mixer control VC-SEL instead\n");
break;
case VoIP_Ioctl_SetCodecType:
aTrace(LOG_ALSA_INTERFACE,
"M:Inside VoIP_Ioctl_SetCodecType\n");
copy_from_user(&val, (int __user *)arg,
sizeof(voip_codec_type_data_t));
if (val.ul_dl_type == VoIP_UL) {
pchip->voip_data.codec_type_ul = val.codec_type;
aTrace(LOG_ALSA_INTERFACE,
" VoIP_Ioctl_SetCodecType codec_type %ld,\n",
pchip->voip_data.codec_type_ul);
/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
if (!pvoip)
break;
pvoip->codec_type_ul = pchip->voip_data.codec_type_ul;
} else {
pchip->voip_data.codec_type_dl = val.codec_type;
aTrace(LOG_ALSA_INTERFACE,
" VoIP_Ioctl_SetCodecType codec_type %ld,\n",
pchip->voip_data.codec_type_dl);
/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
if (!pvoip)
break;
pvoip->codec_type_dl = pchip->voip_data.codec_type_dl;
}
/*Check whether in a VoLTE call*/
/*If no, do nothing.*/
/*If yes, do the NB<->WB switching*/
if (isvolte) {
BRCM_AUDIO_Param_RateChange_t param_rate_change;
if (pvoip->ulstarted == 0 && pvoip->dlstarted == 0)
break;
if (!(pvoip->buffer_handle))
break;
if (!(pvoip->buffer_handle->drv_handle))
break;
AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
AUDIO_DRIVER_SET_AMR, &pchip->voip_data);
if (((val.ul_dl_type == VoIP_UL) &&
((pvoip->codec_type_ul == 4) ||
(pvoip->codec_type_ul == 5)))
|| ((val.ul_dl_type == VoIP_DL) &&
((pvoip->codec_type_dl == 4) ||
(pvoip->codec_type_dl == 5))))
/* VOIP_PCM_16K or VOIP_AMR_WB_MODE_7k */
param_rate_change.codecID = 0x0A;
else
param_rate_change.codecID = 0x06;
AUDIO_Ctrl_Trigger(ACTION_AUD_RateChange,
&param_rate_change, NULL, 0);
}
break;
case VoIP_Ioctl_SetBitrate:
get_user(data, (int __user *)arg);
pchip->voip_data.bitrate_index = (u32) data;
aTrace(LOG_ALSA_INTERFACE,
" VoIP_Ioctl_SetBitrate bitrate_index %ld,\n",
pchip->voip_data.bitrate_index);
/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
if (!pvoip)
break;
if (isvolte) {
if (pvoip->ulstarted == 0 && pvoip->dlstarted == 0)
break;
if (!(pvoip->buffer_handle))
break;
if (!(pvoip->buffer_handle->drv_handle))
break;
AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
AUDIO_DRIVER_SET_AMR, &pchip->voip_data);
}
break;
case VoIP_Ioctl_GetSource:
{
s32 *psel;
psel = pchip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1]
.iLineSelect;
data = (int)psel[0];
put_user(data, (int __user *)arg);
}
break;
case VoIP_Ioctl_GetSink:
{
s32 *psel;
psel = pchip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1]
.iLineSelect;
data = (int)psel[1];
put_user(data, (int __user *)arg);
}
break;
case VoIP_Ioctl_GetCodecType:
aTrace(LOG_ALSA_INTERFACE,
"voip_ioctl in VoIP_Ioctl_GetCodecType");
copy_from_user(&val, (int __user *)arg,
sizeof(voip_codec_type_data_t));
if (val.ul_dl_type == VoIP_UL)
val.codec_type = (int)pchip->voip_data.codec_type_ul;
else
val.codec_type = (int)pchip->voip_data.codec_type_dl;
copy_to_user((int __user *)arg, &val,
sizeof(voip_codec_type_data_t));
break;
case VoIP_Ioctl_GetBitrate:
data = (int)pchip->voip_data.bitrate_index;
put_user(data, (int __user *)arg);
break;
case VoIP_Ioctl_GetMode:
{
AudioMode_t mode = AUDCTRL_GetAudioMode();
put_user((int)mode, (int __user *)arg);
aTrace(LOG_ALSA_INTERFACE,
" VoIP_Ioctl_GetMode mode %d,\n",
mode);
}
break;
case VoIP_Ioctl_SetMode:
aTrace(LOG_ALSA_INTERFACE ,
" Warning: VoIP_Ioctl_SetMode"
"is depreciated, please "
"use mixer control VC-SEL instead\n");
break;
case VoIP_Ioctl_SetVoLTEDTX:
get_user(data, (int __user *)arg);
pchip->voip_data.isDTXEnabled = (u8) data;
aTrace(LOG_ALSA_INTERFACE, " VoIP_Ioctl_SetVoLTEDTX %d,\n",
pchip->voip_data.isDTXEnabled);
/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
if (!pvoip)
break;
if (!(pvoip->buffer_handle))
break;
if (!(pvoip->buffer_handle->drv_handle))
break;
AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
AUDIO_DRIVER_SET_DTX, &pchip->voip_data);
break;
case VoIP_Ioctl_SetVoLTEFlag:
get_user(data, (int __user *)arg);
pchip->voip_data.isVoLTE = (u8) data;
aTrace(LOG_ALSA_INTERFACE, " VoIP_Ioctl_SetFlag isVoLTE %d,\n",
pchip->voip_data.isVoLTE);
isvolte = pchip->voip_data.isVoLTE;
break;
case VoIP_Ioctl_GetVoLTEFlag:
data = (int)pchip->voip_data.isVoLTE;
put_user(data, (int __user *)arg);
break;
case DSPCtrl_Ioctl_SPCtrl:
if (dataptr == NULL)
dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
else
memset(dataptr, 0, sizeof(UserCtrl_data_t));
if (!dataptr)
return -ENOMEM;
ret =
copy_from_user(dataptr, (int __user *)arg,
sizeof(UserCtrl_data_t));
enable = (Boolean) dataptr->data[0];
size = dataptr->data[1];
ret =
AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_CTRL, enable, size,
(void *)&(dataptr->data[2]));
if (!enable) {
kfree(dataptr);
dataptr = NULL;
}
break;
case DSPCtrl_Ioctl_SPSetVar:
/*
* Will move this part later after we separate the voip and
* dspctrl connections.
*/
if (dataptr == NULL)
dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
else
memset(dataptr, 0, sizeof(UserCtrl_data_t));
if (!dataptr)
return -ENOMEM;
ret =
copy_from_user(dataptr, (int __user *)arg,
sizeof(UserCtrl_data_t));
size = dataptr->data[0];
ret =
AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_VAR, enable, size,
(void *)&(dataptr->data[2]));
break;
case DSPCtrl_Ioctl_SPQuery:
if (dataptr == NULL)
dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
else
memset(dataptr, 0, sizeof(UserCtrl_data_t));
if (!dataptr)
return -ENOMEM;
ret =
AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_QUERY, enable, size,
(void *)dataptr);
if (ret < 0)
return ret;
if (copy_to_user
((int __user *)arg, dataptr, sizeof(UserCtrl_data_t)))
return -EFAULT;
break;
case DSPCtrl_Ioctl_EQCtrl:
if (dataptr == NULL)
dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
else
memset(dataptr, 0, sizeof(UserCtrl_data_t));
if (!dataptr)
return -ENOMEM;
if (copy_from_user
(dataptr, (int __user *)arg, sizeof(UserCtrl_data_t)))
return -EFAULT;
enable = (Boolean) dataptr->data[0];
ret =
AUDDRV_User_CtrlDSP(AUDDRV_USER_EQ_CTRL, enable, size,
(void *)&(dataptr->data[2]));
if (!enable) {
kfree(dataptr);
dataptr = NULL;
}
break;
case Ctrl_Ioctl_SWEQParm:
aTrace(LOG_ALSA_INTERFACE,
"ALSA-CAPH hwdep_ioctl Ctrl_Ioctl_SWEQParm");
eq = kzalloc(sizeof(*eq), GFP_KERNEL);
if (eq == NULL) {
aError("treq_sysparm_t mem alloc failed");
return -ENOMEM;
}
/* get the sysparm from driver
SW EQ is only for music playback for now*/
if (copy_from_user(eq, (int __user *)arg,
sizeof(struct treq_sysparm_t))) {
if (eq != NULL) {
kfree(eq);
eq = NULL;
}
return -EFAULT;
}
ret = AUDDRV_Get_TrEqParm((void *)eq,
sizeof(*eq), AUDIO_APP_MUSIC,
(eq->data)[TREQ_DATA_SIZE-1]);
if (!ret) {
if (copy_to_user((void __user *)arg, eq,
sizeof(*eq))) {
if (eq != NULL) {
kfree(eq);
eq = NULL;
}
return -EFAULT;
}
}
if (eq != NULL) {
kfree(eq);
eq = NULL;
}
break;
default:
ret = -ENOTTY;
break;
}
return ret;
}
static ssize_t voip_mmap(struct file *filep, struct vm_area_struct *vma)
{
return 0;
}
static unsigned int voip_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
bcm_caph_hwdep_voip_t *pvoip;
voipdev *pvoipchrdevpvtdata;
pvoipchrdevpvtdata = (voipdev *)file->private_data;
pvoip = (bcm_caph_hwdep_voip_t *)pvoipchrdevpvtdata->pvoip;
if (!pvoip) {
aError("returning from poll\n");
return 0;
}
poll_wait(file, &pvoip->sleep, wait);
if (pvoip->status == voip_hwdep_status_started) {
if (pvoip->frames_available_to_read > 0)
mask = POLLIN | POLLRDNORM;
if (pvoip->writecount > 0) /* buffer available to write */
mask |= POLLOUT | POLLWRNORM;
}
/* DEBUG("voip_poll mask %ld\n",mask); */
return mask;
}
static struct class *voipclass;
/* File operations for audio logging */
static const struct file_operations voip_fops = {
.owner = THIS_MODULE,
.open = voip_open,
.read = voip_read,
.write = voip_write,
.release = voip_release,
.unlocked_ioctl = voip_ioctl,
.mmap = voip_mmap,
.poll = voip_poll,
#if 0
.dsp_status = hwdep_dsp_status,
.poll = hwdep_poll
#endif
};
int voipdevicecreate(voipdev *pvoipchrdevpvtdata)
{
int err = 0;
aError("M:Inside voipdevicecreate\n");
err = register_chrdev_region(MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0),
1, "bcm_voip_chrdev");
if (err < 0)
return err;
cdev_init(&pvoipchrdevpvtdata->voipcdev, &voip_fops);
pvoipchrdevpvtdata->voipcdev.owner = THIS_MODULE;
pvoipchrdevpvtdata->voipcdev.ops = &voip_fops;
if (cdev_add(&pvoipchrdevpvtdata->voipcdev,
MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0), 1)) {
unregister_chrdev_region(MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0), 1);
return 1;
}
voipclass = class_create(THIS_MODULE, "bcm_voip_chrdev");
if (IS_ERR(voipclass)) {
cdev_del(&pvoipchrdevpvtdata->voipcdev);
unregister_chrdev_region(MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0), 1);
return PTR_ERR(voipclass);
}
device_create(voipclass, NULL, MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0), NULL,
"bcm_voip_chrdev");
return err;
}
int voipdevicedestroy(voipdev *pvoipchrdevpvtdata)
{
device_destroy(voipclass, MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0));
class_destroy(voipclass);
cdev_del(&pvoipchrdevpvtdata->voipcdev);
unregister_chrdev_region(MKDEV(BCM_VOIP_CHRDEV_MAJOR, 0), 1);
return 0;
}
#endif
void voip_log_capture(CAPTURE_POINT_t log_point, unsigned char *buf,
int size) {
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
if (voip_log.voip_log_on <= 0)
return;
if (log_point == AUD_LOG_VOCODER_UL) {
substream = &voip_log.substream_ul;
runtime = &voip_log.runtime_ul;
if (mutex_lock_interruptible(&voip_log.voip_ul_mutex))
return;
} else {
substream = &voip_log.substream_dl;
runtime = &voip_log.runtime_dl;
if (mutex_lock_interruptible(&voip_log.voip_dl_mutex))
return;
}
runtime->rate = AUDIO_SAMPLING_RATE_16000;
runtime->sample_bits = 16;
runtime->channels = AUDIO_CHANNEL_MONO;
runtime->dma_area = buf;
runtime->dma_bytes = 2*size;
substream->runtime = runtime;
if (log_point == AUD_LOG_VOCODER_UL)
mutex_unlock(&voip_log.voip_ul_mutex);
else
mutex_unlock(&voip_log.voip_dl_mutex);
logmsg_ready(substream, log_point);
}