audio-lnx: Rename folders to new flat structure.

Kernel audio drivers can be categorised into below folders.
asoc - ALSA based drivers,
asoc/codecs - codec drivers,
ipc - APR IPC communication drivers,
dsp - DSP low level drivers/Audio ION/ADSP Loader,
dsp/codecs - Native encoders and decoders,
soc - SoC based drivers(pinctrl/regmap/soundwire)

Restructure drivers to above folder format.
Include directories also follow above format.

Change-Id: I8fa0857baaacd47db126fb5c1f1f5ed7e886dbc0
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
Esse commit está contido em:
Laxminath Kasam
2017-08-01 22:02:15 +05:30
commit de Martin Fick
commit 605b42f92c
269 arquivos alterados com 423 adições e 2706 exclusões

5
dsp/codecs/Makefile Arquivo normal
Ver arquivo

@@ -0,0 +1,5 @@
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o g711mlaw_in.o g711alaw_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_alac.o audio_ape.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += q6audio_v2.o q6audio_v2_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_g711mlaw.o audio_g711alaw.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o audio_hwacc_effects.o

709
dsp/codecs/aac_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,709 @@
/*
* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_aac.h>
#include <linux/compat.h>
#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 5 frames in buffer with meta */
#define FRAME_SIZE (1 + ((1536+sizeof(struct meta_out_dsp)) * 5))
#define AAC_FORMAT_ADTS 65535
#define MAX_SAMPLE_RATE_384K 384000
static long aac_in_ioctl_shared(struct file *file, unsigned int cmd, void *arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_aac_enc_config *enc_cfg;
struct msm_audio_aac_config *aac_config;
uint32_t aac_mode = AAC_ENC_MODE_AAC_LC;
enc_cfg = audio->enc_cfg;
aac_config = audio->codec_cfg;
/* ENCODE CFG (after new set of API's are published )bharath*/
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
pr_info("%s:AUDIO_START already over\n", __func__);
rc = 0;
break;
}
if (audio->opened) {
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed\n",
__func__, audio->ac->session);
break;
}
} else {
if (audio->feedback == NON_TUNNEL_MODE) {
pr_debug("%s: starting in non_tunnel mode",
__func__);
rc = q6asm_open_read_write(audio->ac,
FORMAT_MPEG4_AAC, FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:open read write failed\n",
__func__);
break;
}
}
if (audio->feedback == TUNNEL_MODE) {
pr_debug("%s: starting in tunnel mode",
__func__);
rc = q6asm_open_read(audio->ac,
FORMAT_MPEG4_AAC);
if (rc < 0) {
pr_err("%s:open read failed\n",
__func__);
break;
}
}
audio->stopped = 0;
}
pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
aac_config->sbr_ps_on_flag, aac_config->sbr_on_flag);
if (aac_config->sbr_ps_on_flag)
aac_mode = AAC_ENC_MODE_EAAC_P;
else if (aac_config->sbr_on_flag)
aac_mode = AAC_ENC_MODE_AAC_P;
else
aac_mode = AAC_ENC_MODE_AAC_LC;
rc = q6asm_enc_cfg_blk_aac(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->sample_rate,
enc_cfg->channels,
enc_cfg->bit_rate,
aac_mode,
enc_cfg->stream_format);
if (rc < 0) {
pr_err("%s:session id %d: cmd media format block failed\n",
__func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed\n",
__func__, audio->ac->session);
break;
}
}
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac);
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:session id %d: Rxed AUDIO_STOP\n", __func__,
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
break;
}
case AUDIO_GET_AAC_ENC_CONFIG: {
struct msm_audio_aac_enc_config *cfg;
struct msm_audio_aac_enc_config *enc_cfg;
cfg = (struct msm_audio_aac_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer for %s\n",
__func__, "AUDIO_GET_AAC_CONFIG");
rc = -EINVAL;
break;
}
memset(cfg, 0, sizeof(*cfg));
enc_cfg = audio->enc_cfg;
if (enc_cfg->channels == CH_MODE_MONO)
cfg->channels = 1;
else
cfg->channels = 2;
cfg->sample_rate = enc_cfg->sample_rate;
cfg->bit_rate = enc_cfg->bit_rate;
switch (enc_cfg->stream_format) {
case 0x00:
cfg->stream_format = AUDIO_AAC_FORMAT_ADTS;
break;
case 0x01:
cfg->stream_format = AUDIO_AAC_FORMAT_LOAS;
break;
case 0x02:
cfg->stream_format = AUDIO_AAC_FORMAT_ADIF;
break;
default:
case 0x03:
cfg->stream_format = AUDIO_AAC_FORMAT_RAW;
}
pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d bitrate=%d\n",
__func__, audio->ac->session,
cfg->stream_format, cfg->sample_rate, cfg->bit_rate);
break;
}
case AUDIO_SET_AAC_ENC_CONFIG: {
struct msm_audio_aac_enc_config *cfg;
struct msm_audio_aac_enc_config *enc_cfg;
uint32_t min_bitrate, max_bitrate;
cfg = (struct msm_audio_aac_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer for %s\n",
"AUDIO_SET_AAC_ENC_CONFIG", __func__);
rc = -EINVAL;
break;
}
enc_cfg = audio->enc_cfg;
pr_debug("%s:session id %d: Set-aac-cfg: stream=%d\n", __func__,
audio->ac->session, cfg->stream_format);
switch (cfg->stream_format) {
case AUDIO_AAC_FORMAT_ADTS:
enc_cfg->stream_format = 0x00;
break;
case AUDIO_AAC_FORMAT_LOAS:
enc_cfg->stream_format = 0x01;
break;
case AUDIO_AAC_FORMAT_ADIF:
enc_cfg->stream_format = 0x02;
break;
case AUDIO_AAC_FORMAT_RAW:
enc_cfg->stream_format = 0x03;
break;
default:
pr_err("%s:session id %d: unsupported AAC format %d\n",
__func__, audio->ac->session,
cfg->stream_format);
rc = -EINVAL;
break;
}
if (cfg->channels == 1) {
cfg->channels = CH_MODE_MONO;
} else if (cfg->channels == 2) {
cfg->channels = CH_MODE_STEREO;
} else {
rc = -EINVAL;
break;
}
if (cfg->sample_rate > MAX_SAMPLE_RATE_384K) {
pr_err("%s: ERROR: invalid sample rate = %u",
__func__, cfg->sample_rate);
rc = -EINVAL;
break;
}
min_bitrate = ((cfg->sample_rate)*(cfg->channels))/2;
/* This calculation should be based on AAC mode. But we cannot
* get AAC mode in this setconfig. min_bitrate's logical max
* value is 24000. So if min_bitrate is higher than 24000,
* choose 24000.
*/
if (min_bitrate > 24000)
min_bitrate = 24000;
max_bitrate = 6*(cfg->sample_rate)*(cfg->channels);
if (max_bitrate > 192000)
max_bitrate = 192000;
if ((cfg->bit_rate < min_bitrate) ||
(cfg->bit_rate > max_bitrate)) {
pr_err("%s: bitrate permissible: max=%d, min=%d\n",
__func__, max_bitrate, min_bitrate);
pr_err("%s: ERROR in setting bitrate = %d\n",
__func__, cfg->bit_rate);
rc = -EINVAL;
break;
}
enc_cfg->sample_rate = cfg->sample_rate;
enc_cfg->channels = cfg->channels;
enc_cfg->bit_rate = cfg->bit_rate;
pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x bitrate=0x%x, format(adts/raw) = %d\n",
__func__, audio->ac->session, enc_cfg->sample_rate,
enc_cfg->channels, enc_cfg->bit_rate,
enc_cfg->stream_format);
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config *aac_cfg;
struct msm_audio_aac_config *audio_aac_cfg;
struct msm_audio_aac_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
audio_aac_cfg = audio->codec_cfg;
aac_cfg = (struct msm_audio_aac_config *)arg;
if (aac_cfg == NULL) {
pr_err("%s: NULL config pointer %s\n",
__func__, "AUDIO_SET_AAC_CONFIG");
rc = -EINVAL;
break;
}
pr_debug("%s:session id %d: AUDIO_SET_AAC_CONFIG: sbr_flag = %d sbr_ps_flag = %d\n",
__func__, audio->ac->session, aac_cfg->sbr_on_flag,
aac_cfg->sbr_ps_on_flag);
audio_aac_cfg->sbr_on_flag = aac_cfg->sbr_on_flag;
audio_aac_cfg->sbr_ps_on_flag = aac_cfg->sbr_ps_on_flag;
if ((audio_aac_cfg->sbr_on_flag == 1) ||
(audio_aac_cfg->sbr_ps_on_flag == 1)) {
if (enc_cfg->sample_rate < 24000) {
pr_err("%s: ERROR in setting samplerate = %d\n",
__func__, enc_cfg->sample_rate);
rc = -EINVAL;
break;
}
}
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
static long aac_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = aac_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AAC_ENC_CONFIG: {
struct msm_audio_aac_enc_config cfg;
rc = aac_in_ioctl_shared(file, cmd, &cfg);
if (rc) {
pr_err("%s:AUDIO_GET_AAC_ENC_CONFIG failed. rc=%d\n",
__func__, rc);
break;
}
if (copy_to_user((void *)arg, &cfg, sizeof(cfg))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AAC_ENC_CONFIG: {
struct msm_audio_aac_enc_config cfg;
if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = aac_in_ioctl_shared(file, cmd, &cfg);
if (rc)
pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
__func__, rc);
break;
}
case AUDIO_GET_AAC_CONFIG: {
if (copy_to_user((void *)arg, &audio->codec_cfg,
sizeof(struct msm_audio_aac_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config aac_cfg;
if (copy_from_user(&aac_cfg, (void *)arg,
sizeof(struct msm_audio_aac_config))) {
pr_err("%s: copy_to_user for AUDIO_SET_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = aac_in_ioctl_shared(file, cmd, &aac_cfg);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. rc=%d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd=%d\n", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_aac_enc_config32 {
u32 channels;
u32 sample_rate;
u32 bit_rate;
u32 stream_format;
};
struct msm_audio_aac_config32 {
s16 format;
u16 audio_object;
u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
u16 aac_section_data_resilience_flag;
u16 aac_scalefactor_data_resilience_flag;
u16 aac_spectral_data_resilience_flag;
u16 sbr_on_flag;
u16 sbr_ps_on_flag;
u16 dual_mono_mode;
u16 channel_configuration;
u16 sample_rate;
};
enum {
AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32),
AUDIO_SET_AAC_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_aac_enc_config32),
AUDIO_GET_AAC_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config32)
};
static long aac_in_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = aac_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AAC_ENC_CONFIG_32: {
struct msm_audio_aac_enc_config cfg;
struct msm_audio_aac_enc_config32 cfg_32;
memset(&cfg_32, 0, sizeof(cfg_32));
cmd = AUDIO_GET_AAC_ENC_CONFIG;
rc = aac_in_ioctl_shared(file, cmd, &cfg);
if (rc) {
pr_err("%s:AUDIO_GET_AAC_ENC_CONFIG_32 failed. Rc= %d\n",
__func__, rc);
break;
}
cfg_32.channels = cfg.channels;
cfg_32.sample_rate = cfg.sample_rate;
cfg_32.bit_rate = cfg.bit_rate;
cfg_32.stream_format = cfg.stream_format;
if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AAC_ENC_CONFIG_32: {
struct msm_audio_aac_enc_config cfg;
struct msm_audio_aac_enc_config32 cfg_32;
if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_GET_AAC_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.channels = cfg_32.channels;
cfg.sample_rate = cfg_32.sample_rate;
cfg.bit_rate = cfg_32.bit_rate;
cfg.stream_format = cfg_32.stream_format;
/* The command should be converted from 32 bit to normal
* before the shared ioctl is called as shared ioctl
* can process only normal commands
*/
cmd = AUDIO_SET_AAC_ENC_CONFIG;
rc = aac_in_ioctl_shared(file, cmd, &cfg);
if (rc)
pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG_32 failed. rc=%d\n",
__func__, rc);
break;
}
case AUDIO_GET_AAC_CONFIG_32: {
struct msm_audio_aac_config *aac_config;
struct msm_audio_aac_config32 aac_config_32;
aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
aac_config_32.format = aac_config->format;
aac_config_32.audio_object = aac_config->audio_object;
aac_config_32.ep_config = aac_config->ep_config;
aac_config_32.aac_section_data_resilience_flag =
aac_config->aac_section_data_resilience_flag;
aac_config_32.aac_scalefactor_data_resilience_flag =
aac_config->aac_scalefactor_data_resilience_flag;
aac_config_32.aac_spectral_data_resilience_flag =
aac_config->aac_spectral_data_resilience_flag;
aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
aac_config_32.channel_configuration =
aac_config->channel_configuration;
aac_config_32.sample_rate = aac_config->sample_rate;
if (copy_to_user((void *)arg, &aac_config_32,
sizeof(aac_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG_32: {
struct msm_audio_aac_config aac_cfg;
struct msm_audio_aac_config32 aac_cfg_32;
if (copy_from_user(&aac_cfg_32, (void *)arg,
sizeof(aac_cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
aac_cfg.format = aac_cfg_32.format;
aac_cfg.audio_object = aac_cfg_32.audio_object;
aac_cfg.ep_config = aac_cfg_32.ep_config;
aac_cfg.aac_section_data_resilience_flag =
aac_cfg_32.aac_section_data_resilience_flag;
aac_cfg.aac_scalefactor_data_resilience_flag =
aac_cfg_32.aac_scalefactor_data_resilience_flag;
aac_cfg.aac_spectral_data_resilience_flag =
aac_cfg_32.aac_spectral_data_resilience_flag;
aac_cfg.sbr_on_flag = aac_cfg_32.sbr_on_flag;
aac_cfg.sbr_ps_on_flag = aac_cfg_32.sbr_ps_on_flag;
aac_cfg.dual_mono_mode = aac_cfg_32.dual_mono_mode;
aac_cfg.channel_configuration =
aac_cfg_32.channel_configuration;
aac_cfg.sample_rate = aac_cfg_32.sample_rate;
cmd = AUDIO_SET_AAC_CONFIG;
rc = aac_in_ioctl_shared(file, cmd, &aac_cfg);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d\n", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#else
#define aac_in_compat_ioctl NULL
#endif
static int aac_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_aac_enc_config *enc_cfg;
struct msm_audio_aac_config *aac_config;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
aac_config = audio->codec_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 1536;
audio->max_frames_per_buf = 5;
enc_cfg->sample_rate = 8000;
enc_cfg->channels = 1;
enc_cfg->bit_rate = 16000;
enc_cfg->stream_format = 0x00;/* 0:ADTS, 3:RAW */
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
aac_config->format = AUDIO_AAC_FORMAT_ADTS;
aac_config->audio_object = AUDIO_AAC_OBJECT_LC;
aac_config->sbr_on_flag = 0;
aac_config->sbr_ps_on_flag = 0;
aac_config->channel_configuration = 1;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->enc_cfg);
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
/* open aac encoder in tunnel mode */
audio->buf_cfg.frames_per_buf = 0x01;
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
audio->buf_cfg.meta_info_enable = 0x01;
pr_info("%s:session id %d: NT mode encoder success\n", __func__,
audio->ac->session);
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_MPEG4_AAC);
if (rc < 0) {
pr_err("%s:session id %d: Tunnel Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__,
audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
audio->buf_cfg.meta_info_enable = 0x00;
pr_info("%s:session id %d: T mode encoder success\n", __func__,
audio->ac->session);
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
audio->reset_event = false;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = aac_in_compat_ioctl;
audio->enc_ioctl = aac_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = aac_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
.compat_ioctl = audio_in_compat_ioctl
};
struct miscdevice audio_aac_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_aac_in",
.fops = &audio_in_fops,
};
static int __init aac_in_init(void)
{
return misc_register(&audio_aac_in_misc);
}
device_initcall(aac_in_init);

402
dsp/codecs/amrnb_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,402 @@
/*
* Copyright (c) 2010-2012, 2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio_amrnb.h>
#include <linux/compat.h>
#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((32+sizeof(struct meta_out_dsp)) * 10))
static long amrnb_in_ioctl_shared(struct file *file,
unsigned int cmd, void *arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
enc_cfg = audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
pr_info("%s:AUDIO_START already over\n", __func__);
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed\n",
__func__, audio->ac->session);
break;
}
rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->band_mode,
enc_cfg->dtx_enable);
if (rc < 0) {
pr_err("%s:session id %d: cmd amrnb media format block failed\n",
__func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed\n",
__func__, audio->ac->session);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
__func__, audio->ac->session,
audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:AUDIO_STOP\n", __func__);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
break;
}
case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
struct msm_audio_amrnb_enc_config_v2 *cfg;
struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
cfg = (struct msm_audio_amrnb_enc_config_v2 *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer for %s\n",
__func__,
"AUDIO_SET_AMRNB_ENC_CONFIG_V2");
rc = -EINVAL;
break;
}
enc_cfg = audio->enc_cfg;
if (cfg->band_mode > 8 ||
cfg->band_mode < 1) {
pr_err("%s:session id %d: invalid band mode\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
/* AMR NB encoder accepts values between 0-7
* while openmax provides value between 1-8
* as per spec
*/
enc_cfg->band_mode = (cfg->band_mode - 1);
enc_cfg->dtx_enable = (cfg->dtx_enable ? 1 : 0);
enc_cfg->frame_format = 0;
pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
__func__, audio->ac->session,
enc_cfg->band_mode, enc_cfg->dtx_enable);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
static long amrnb_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = amrnb_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_amrnb_enc_config_v2))) {
pr_err("%s: copy_to_user for AUDIO_GET_AMRNB_ENC_CONFIG_V2 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
struct msm_audio_amrnb_enc_config_v2 cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(cfg))) {
pr_err("%s: copy_from_user for AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = amrnb_in_ioctl_shared(file, cmd, &cfg);
if (rc)
pr_err("%s: AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed. rc=%d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd=%d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_amrnb_enc_config_v2_32 {
u32 band_mode;
u32 dtx_enable;
u32 frame_format;
};
enum {
AUDIO_GET_AMRNB_ENC_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+2),
struct msm_audio_amrnb_enc_config_v2_32),
AUDIO_SET_AMRNB_ENC_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+3),
struct msm_audio_amrnb_enc_config_v2_32)
};
static long amrnb_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = amrnb_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AMRNB_ENC_CONFIG_V2_32: {
struct msm_audio_amrnb_enc_config_v2 *amrnb_config;
struct msm_audio_amrnb_enc_config_v2_32 amrnb_config_32;
memset(&amrnb_config_32, 0, sizeof(amrnb_config_32));
amrnb_config =
(struct msm_audio_amrnb_enc_config_v2 *)audio->enc_cfg;
amrnb_config_32.band_mode = amrnb_config->band_mode;
amrnb_config_32.dtx_enable = amrnb_config->dtx_enable;
amrnb_config_32.frame_format = amrnb_config->frame_format;
if (copy_to_user((void *)arg, &amrnb_config_32,
sizeof(amrnb_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AMRNB_ENC_CONFIG_V2_32 failed",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AMRNB_ENC_CONFIG_V2_32: {
struct msm_audio_amrnb_enc_config_v2_32 cfg_32;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AMRNB_ENC_CONFIG_V2_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cmd = AUDIO_SET_AMRNB_ENC_CONFIG_V2;
rc = amrnb_in_ioctl_shared(file, cmd, &cfg_32);
if (rc)
pr_err("%s:AUDIO_SET_AMRNB_ENC_CONFIG_V2 failed rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#else
#define amrnb_in_compat_ioctl NULL
#endif
static int amrnb_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 32;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->band_mode = 7;
enc_cfg->dtx_enable = 0;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open amrnb encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: NT mode encoder success\n",
__func__, audio->ac->session);
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__, audio->ac->session,
rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: T mode encoder success\n",
__func__, audio->ac->session);
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = amrnb_in_compat_ioctl;
audio->enc_ioctl = amrnb_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = amrnb_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
.compat_ioctl = audio_in_compat_ioctl
};
struct miscdevice audio_amrnb_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amrnb_in",
.fops = &audio_in_fops,
};
static int __init amrnb_in_init(void)
{
return misc_register(&audio_amrnb_in_misc);
}
device_initcall(amrnb_in_init);

400
dsp/codecs/amrwb_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,400 @@
/*
* Copyright (c) 2011-2012, 2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/msm_audio_amrwb.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/compat.h>
#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((61+sizeof(struct meta_out_dsp)) * 10))
static long amrwb_in_ioctl_shared(struct file *file,
unsigned int cmd, void *arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_amrwb_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
pr_info("%s:AUDIO_START already over\n", __func__);
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed\n",
__func__, audio->ac->session);
break;
}
rc = q6asm_enc_cfg_blk_amrwb(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->band_mode,
enc_cfg->dtx_enable);
if (rc < 0) {
pr_err("%s:session id %d: cmd amrwb media format block failed\n",
__func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed\n",
__func__, audio->ac->session);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
__func__, audio->ac->session,
audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:AUDIO_STOP\n", __func__);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
break;
}
case AUDIO_SET_AMRWB_ENC_CONFIG: {
struct msm_audio_amrwb_enc_config *cfg;
struct msm_audio_amrwb_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
cfg = (struct msm_audio_amrwb_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer for %s\n",
__func__, "AUDIO_SET_AMRWB_ENC_CONFIG");
rc = -EINVAL;
break;
}
if (cfg->band_mode > 8) {
pr_err("%s:session id %d: invalid band mode\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
/* ToDo: AMR WB encoder accepts values between 0-8
* while openmax provides value between 9-17
* as per spec
*/
enc_cfg->band_mode = cfg->band_mode;
enc_cfg->dtx_enable = (cfg->dtx_enable ? 1 : 0);
/* Currently DSP does not support different frameformat */
enc_cfg->frame_format = 0;
pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
__func__, audio->ac->session,
enc_cfg->band_mode, enc_cfg->dtx_enable);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
static long amrwb_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = amrwb_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AMRWB_ENC_CONFIG: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_amrwb_enc_config)))
pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
case AUDIO_SET_AMRWB_ENC_CONFIG: {
struct msm_audio_amrwb_enc_config cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(cfg))) {
pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = amrwb_in_ioctl_shared(file, cmd, &cfg);
if (rc)
pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_amrwb_enc_config_32 {
u32 band_mode;
u32 dtx_enable;
u32 frame_format;
};
enum {
AUDIO_GET_AMRWB_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0),
struct msm_audio_amrwb_enc_config_32),
AUDIO_SET_AMRWB_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1),
struct msm_audio_amrwb_enc_config_32)
};
static long amrwb_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = amrwb_in_ioctl_shared(file, cmd, NULL);
break;
}
case AUDIO_GET_AMRWB_ENC_CONFIG_32: {
struct msm_audio_amrwb_enc_config *amrwb_config;
struct msm_audio_amrwb_enc_config_32 amrwb_config_32;
memset(&amrwb_config_32, 0, sizeof(amrwb_config_32));
amrwb_config =
(struct msm_audio_amrwb_enc_config *)audio->enc_cfg;
amrwb_config_32.band_mode = amrwb_config->band_mode;
amrwb_config_32.dtx_enable = amrwb_config->dtx_enable;
amrwb_config_32.frame_format = amrwb_config->frame_format;
if (copy_to_user((void *)arg, &amrwb_config_32,
sizeof(struct msm_audio_amrwb_enc_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AMRWB_ENC_CONFIG_32: {
struct msm_audio_amrwb_enc_config cfg_32;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cmd = AUDIO_SET_AMRWB_ENC_CONFIG;
rc = amrwb_in_ioctl_shared(file, cmd, &cfg_32);
if (rc)
pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#else
#define amrwb_in_compat_ioctl NULL
#endif
static int amrwb_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_amrwb_enc_config *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrwb_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 32;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->band_mode = 8;
enc_cfg->dtx_enable = 0;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 16000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s:audio[%pK]: Could not allocate memory for audio client\n",
__func__, audio);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open amrwb encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_AMRWB,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: NT mode encoder success\n",
__func__, audio->ac->session);
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_AMRWB);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__, audio->ac->session,
rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: T mode encoder success\n",
__func__, audio->ac->session);
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = amrwb_in_compat_ioctl;
audio->enc_ioctl = amrwb_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = amrwb_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
.compat_ioctl = audio_in_compat_ioctl
};
struct miscdevice audio_amrwb_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amrwb_in",
.fops = &audio_in_fops,
};
static int __init amrwb_in_init(void)
{
return misc_register(&audio_amrwb_in_misc);
}
device_initcall(amrwb_in_init);

474
dsp/codecs/audio_aac.c Arquivo normal
Ver arquivo

@@ -0,0 +1,474 @@
/* aac audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/msm_audio_aac.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
#define AUDIO_AAC_DUAL_MONO_INVALID -1
#define PCM_BUFSZ_MIN_AAC ((8*1024) + sizeof(struct dec_meta_out))
static struct miscdevice audio_aac_misc;
static struct ws_mgr audio_aac_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_aac_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_aac_cfg aac_cfg;
struct msm_audio_aac_config *aac_config;
uint32_t sbr_ps = 0x00;
pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac, 0, 0);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
/* turn on both sbr and ps */
rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
if (rc < 0)
pr_err("sbr-ps enable failed\n");
aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
if (aac_config->sbr_ps_on_flag)
aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
else if (aac_config->sbr_on_flag)
aac_cfg.aot = AAC_ENC_MODE_AAC_P;
else
aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
switch (aac_config->format) {
case AUDIO_AAC_FORMAT_ADTS:
aac_cfg.format = 0x00;
break;
case AUDIO_AAC_FORMAT_LOAS:
aac_cfg.format = 0x01;
break;
case AUDIO_AAC_FORMAT_ADIF:
aac_cfg.format = 0x02;
break;
default:
case AUDIO_AAC_FORMAT_RAW:
aac_cfg.format = 0x03;
}
aac_cfg.ep_config = aac_config->ep_config;
aac_cfg.section_data_resilience =
aac_config->aac_section_data_resilience_flag;
aac_cfg.scalefactor_data_resilience =
aac_config->aac_scalefactor_data_resilience_flag;
aac_cfg.spectral_data_resilience =
aac_config->aac_spectral_data_resilience_flag;
aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
if (audio->feedback == TUNNEL_MODE) {
aac_cfg.sample_rate = aac_config->sample_rate;
aac_cfg.ch_cfg = aac_config->channel_configuration;
} else {
aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
}
pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
__func__, aac_cfg.format,
aac_cfg.aot, aac_cfg.ch_cfg,
aac_cfg.sample_rate);
/* Configure Media format block */
rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
rc = enable_volume_ramp(audio);
if (rc < 0) {
pr_err("%s: Failed to enable volume ramp\n",
__func__);
}
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config *aac_config;
uint16_t sce_left = 1, sce_right = 2;
pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
aac_config = (struct msm_audio_aac_config *)arg;
if (aac_config == NULL) {
pr_err("%s: Invalid config pointer\n", __func__);
rc = -EINVAL;
break;
}
memcpy(audio->codec_cfg, aac_config,
sizeof(struct msm_audio_aac_config));
/* PL_PR is 0 only need to check PL_SR */
if (aac_config->dual_mono_mode >
AUDIO_AAC_DUAL_MONO_PL_SR) {
pr_err("%s:Invalid dual_mono mode =%d\n", __func__,
aac_config->dual_mono_mode);
} else {
/* convert the data from user into sce_left
* and sce_right based on the definitions
*/
pr_debug("%s: modify dual_mono mode =%d\n", __func__,
aac_config->dual_mono_mode);
switch (aac_config->dual_mono_mode) {
case AUDIO_AAC_DUAL_MONO_PL_PR:
sce_left = 1;
sce_right = 1;
break;
case AUDIO_AAC_DUAL_MONO_SL_SR:
sce_left = 2;
sce_right = 2;
break;
case AUDIO_AAC_DUAL_MONO_SL_PR:
sce_left = 2;
sce_right = 1;
break;
case AUDIO_AAC_DUAL_MONO_PL_SR:
default:
sce_left = 1;
sce_right = 2;
break;
}
rc = q6asm_cfg_dual_mono_aac(audio->ac,
sce_left, sce_right);
if (rc < 0)
pr_err("%s:asm cmd dualmono failed rc=%d\n",
__func__, rc);
}
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AAC_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_aac_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config aac_config;
pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
if (copy_from_user(&aac_config, (void *)arg,
sizeof(aac_config))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = audio_ioctl_shared(file, cmd, &aac_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
__func__, audio, rc);
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_aac_config32 {
s16 format;
u16 audio_object;
u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
u16 aac_section_data_resilience_flag;
u16 aac_scalefactor_data_resilience_flag;
u16 aac_spectral_data_resilience_flag;
u16 sbr_on_flag;
u16 sbr_ps_on_flag;
u16 dual_mono_mode;
u16 channel_configuration;
u16 sample_rate;
};
enum {
AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AAC_CONFIG_32: {
struct msm_audio_aac_config *aac_config;
struct msm_audio_aac_config32 aac_config_32;
aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
aac_config_32.format = aac_config->format;
aac_config_32.audio_object = aac_config->audio_object;
aac_config_32.ep_config = aac_config->ep_config;
aac_config_32.aac_section_data_resilience_flag =
aac_config->aac_section_data_resilience_flag;
aac_config_32.aac_scalefactor_data_resilience_flag =
aac_config->aac_scalefactor_data_resilience_flag;
aac_config_32.aac_spectral_data_resilience_flag =
aac_config->aac_spectral_data_resilience_flag;
aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
aac_config_32.channel_configuration =
aac_config->channel_configuration;
aac_config_32.sample_rate = aac_config->sample_rate;
if (copy_to_user((void *)arg, &aac_config_32,
sizeof(aac_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG_32: {
struct msm_audio_aac_config aac_config;
struct msm_audio_aac_config32 aac_config_32;
pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
if (copy_from_user(&aac_config_32, (void *)arg,
sizeof(aac_config_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
aac_config.format = aac_config_32.format;
aac_config.audio_object = aac_config_32.audio_object;
aac_config.ep_config = aac_config_32.ep_config;
aac_config.aac_section_data_resilience_flag =
aac_config_32.aac_section_data_resilience_flag;
aac_config.aac_scalefactor_data_resilience_flag =
aac_config_32.aac_scalefactor_data_resilience_flag;
aac_config.aac_spectral_data_resilience_flag =
aac_config_32.aac_spectral_data_resilience_flag;
aac_config.sbr_on_flag = aac_config_32.sbr_on_flag;
aac_config.sbr_ps_on_flag = aac_config_32.sbr_ps_on_flag;
aac_config.dual_mono_mode = aac_config_32.dual_mono_mode;
aac_config.channel_configuration =
aac_config_32.channel_configuration;
aac_config.sample_rate = aac_config_32.sample_rate;
cmd = AUDIO_SET_AAC_CONFIG;
rc = audio_ioctl_shared(file, cmd, &aac_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
__func__, audio, rc);
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
struct msm_audio_aac_config *aac_config = NULL;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_aac_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
aac_config = audio->codec_cfg;
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AAC;
audio->miscdevice = &audio_aac_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_aac_ws_mgr;
aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_MPEG4_AAC);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open AAC decoder, expected frames is always 1
* audio->buf_cfg.frames_per_buf = 0x01;
*/
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_aac_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_aac_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:aacdec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_aac_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_aac_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_aac",
.fops = &audio_aac_fops,
};
static int __init audio_aac_init(void)
{
int ret = misc_register(&audio_aac_misc);
if (ret == 0)
device_init_wakeup(audio_aac_misc.this_device, true);
audio_aac_ws_mgr.ref_cnt = 0;
mutex_init(&audio_aac_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_aac_init);

435
dsp/codecs/audio_alac.c Arquivo normal
Ver arquivo

@@ -0,0 +1,435 @@
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_alac.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_alac_misc;
static struct ws_mgr audio_alac_ws_mgr;
static const struct file_operations audio_alac_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
static struct dentry *config_debugfs_create_file(const char *name, void *data)
{
return debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)data, &audio_alac_debug_fops);
}
static int alac_channel_map(u8 *channel_mapping, uint32_t channels);
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_alac_cfg alac_cfg;
struct msm_audio_alac_config *alac_config;
u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
if (alac_channel_map(channel_mapping,
audio->pcm_cfg.channel_count)) {
pr_err("%s: setting channel map failed %d\n",
__func__, audio->pcm_cfg.channel_count);
}
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count,
16, /*bits per sample*/
false, false, channel_mapping);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
alac_cfg.frame_length = alac_config->frameLength;
alac_cfg.compatible_version = alac_config->compatVersion;
alac_cfg.bit_depth = alac_config->bitDepth;
alac_cfg.pb = alac_config->pb;
alac_cfg.mb = alac_config->mb;
alac_cfg.kb = alac_config->kb;
alac_cfg.num_channels = alac_config->channelCount;
alac_cfg.max_run = alac_config->maxRun;
alac_cfg.max_frame_bytes = alac_config->maxSize;
alac_cfg.avg_bit_rate = alac_config->averageBitRate;
alac_cfg.sample_rate = alac_config->sampleRate;
alac_cfg.channel_layout_tag = alac_config->channelLayout;
pr_debug("%s: frame_length %d compatible_version %d bit_depth %d pb %d mb %d kb %d num_channels %d max_run %d max_frame_bytes %d avg_bit_rate %d sample_rate %d channel_layout_tag %d\n",
__func__, alac_config->frameLength,
alac_config->compatVersion,
alac_config->bitDepth, alac_config->pb,
alac_config->mb, alac_config->kb,
alac_config->channelCount, alac_config->maxRun,
alac_config->maxSize,
alac_config->averageBitRate,
alac_config->sampleRate,
alac_config->channelLayout);
/* Configure Media format block */
rc = q6asm_media_format_block_alac(audio->ac, &alac_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_ALAC_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_alac_config))) {
pr_err("%s:copy_to_user for AUDIO_GET_ALAC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_ALAC_CONFIG: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_alac_config))) {
pr_err("%s:copy_from_user for AUDIO_SET_ALAC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
default: {
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_alac_config_32 {
u32 frameLength;
u8 compatVersion;
u8 bitDepth;
u8 pb;
u8 mb;
u8 kb;
u8 channelCount;
u16 maxRun;
u32 maxSize;
u32 averageBitRate;
u32 sampleRate;
u32 channelLayout;
};
enum {
AUDIO_GET_ALAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_alac_config_32),
AUDIO_SET_ALAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_alac_config_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_ALAC_CONFIG_32: {
struct msm_audio_alac_config *alac_config;
struct msm_audio_alac_config_32 alac_config_32;
memset(&alac_config_32, 0, sizeof(alac_config_32));
alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
alac_config_32.frameLength = alac_config->frameLength;
alac_config_32.compatVersion =
alac_config->compatVersion;
alac_config_32.bitDepth = alac_config->bitDepth;
alac_config_32.pb = alac_config->pb;
alac_config_32.mb = alac_config->mb;
alac_config_32.kb = alac_config->kb;
alac_config_32.channelCount = alac_config->channelCount;
alac_config_32.maxRun = alac_config->maxRun;
alac_config_32.maxSize = alac_config->maxSize;
alac_config_32.averageBitRate = alac_config->averageBitRate;
alac_config_32.sampleRate = alac_config->sampleRate;
alac_config_32.channelLayout = alac_config->channelLayout;
if (copy_to_user((void *)arg, &alac_config_32,
sizeof(alac_config_32))) {
pr_err("%s: copy_to_user for GET_ALAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_ALAC_CONFIG_32: {
struct msm_audio_alac_config *alac_config;
struct msm_audio_alac_config_32 alac_config_32;
if (copy_from_user(&alac_config_32, (void *)arg,
sizeof(alac_config_32))) {
pr_err("%s: copy_from_user for SET_ALAC_CONFIG_32 failed\n"
, __func__);
rc = -EFAULT;
break;
}
alac_config = (struct msm_audio_alac_config *)audio->codec_cfg;
alac_config->frameLength = alac_config_32.frameLength;
alac_config->compatVersion =
alac_config_32.compatVersion;
alac_config->bitDepth = alac_config_32.bitDepth;
alac_config->pb = alac_config_32.pb;
alac_config->mb = alac_config_32.mb;
alac_config->kb = alac_config_32.kb;
alac_config->channelCount = alac_config_32.channelCount;
alac_config->maxRun = alac_config_32.maxRun;
alac_config->maxSize = alac_config_32.maxSize;
alac_config->averageBitRate = alac_config_32.averageBitRate;
alac_config->sampleRate = alac_config_32.sampleRate;
alac_config->channelLayout = alac_config_32.channelLayout;
break;
}
default: {
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_alac_" + 5];
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (!audio)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_alac_config),
GFP_KERNEL);
if (!audio->codec_cfg) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_alac_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_alac_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_ALAC);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open ALAC decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_ALAC);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
snprintf(name, sizeof(name), "msm_alac_%04x", audio->ac->session);
audio->dentry = config_debugfs_create_file(name, (void *)audio);
if (IS_ERR_OR_NULL(audio->dentry))
pr_debug("debugfs_create_file failed\n");
pr_debug("%s:alacdec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static int alac_channel_map(u8 *channel_mapping, uint32_t channels)
{
u8 *lchannel_mapping;
lchannel_mapping = channel_mapping;
pr_debug("%s: channels passed: %d\n", __func__, channels);
if (channels == 1) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
} else if (channels == 2) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
} else if (channels == 3) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
} else if (channels == 4) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_CS;
} else if (channels == 5) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
} else if (channels == 6) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_LFE;
} else if (channels == 7) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_CS;
lchannel_mapping[6] = PCM_CHANNEL_LFE;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FLC;
lchannel_mapping[2] = PCM_CHANNEL_FRC;
lchannel_mapping[3] = PCM_CHANNEL_FL;
lchannel_mapping[4] = PCM_CHANNEL_FR;
lchannel_mapping[5] = PCM_CHANNEL_LS;
lchannel_mapping[6] = PCM_CHANNEL_RS;
lchannel_mapping[7] = PCM_CHANNEL_LFE;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
return -EINVAL;
}
return 0;
}
static const struct file_operations audio_alac_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_alac_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_alac",
.fops = &audio_alac_fops,
};
static int __init audio_alac_init(void)
{
int ret = misc_register(&audio_alac_misc);
if (ret == 0)
device_init_wakeup(audio_alac_misc.this_device, true);
audio_alac_ws_mgr.ref_cnt = 0;
mutex_init(&audio_alac_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_alac_init);

226
dsp/codecs/audio_amrnb.c Arquivo normal
Ver arquivo

@@ -0,0 +1,226 @@
/* amrnb audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_amrnb_misc;
static struct ws_mgr audio_amrnb_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_amrnb_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
}
return rc;
}
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s: pcm output block config failed rc=%d\n",
__func__, rc);
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s: Audio Start procedure failed rc=%d\n",
__func__, rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
}
return rc;
}
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_amrnb_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_amrnb_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_amrnb_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_AMRNB);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_AMRNB);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_amrnb_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_amrnb_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:amrnb decoder open success, session_id = %d\n", __func__,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio);
return rc;
}
static const struct file_operations audio_amrnb_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl,
};
static struct miscdevice audio_amrnb_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amrnb",
.fops = &audio_amrnb_fops,
};
static int __init audio_amrnb_init(void)
{
int ret = misc_register(&audio_amrnb_misc);
if (ret == 0)
device_init_wakeup(audio_amrnb_misc.this_device, true);
audio_amrnb_ws_mgr.ref_cnt = 0;
mutex_init(&audio_amrnb_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_amrnb_init);

231
dsp/codecs/audio_amrwb.c Arquivo normal
Ver arquivo

@@ -0,0 +1,231 @@
/* amrwb audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/compat.h>
#include <linux/types.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_amrwb_misc;
static struct ws_mgr audio_amrwb_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_amrwb_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
}
return rc;
}
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s: pcm output block config failed rc=%d\n",
__func__, rc);
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s: Audio Start procedure failed rc=%d\n",
__func__, rc);
break;
}
pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
}
return rc;
}
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_amrwb_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_amrwb_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_amrwb_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_AMRWB);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_AMRWB);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_amrwb_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_amrwb_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s: AMRWB dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio);
return rc;
}
static const struct file_operations audio_amrwb_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl,
};
static struct miscdevice audio_amrwb_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amrwb",
.fops = &audio_amrwb_fops,
};
static int __init audio_amrwb_init(void)
{
int ret = misc_register(&audio_amrwb_misc);
if (ret == 0)
device_init_wakeup(audio_amrwb_misc.this_device, true);
audio_amrwb_ws_mgr.ref_cnt = 0;
mutex_init(&audio_amrwb_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_amrwb_init);

397
dsp/codecs/audio_amrwbplus.c Arquivo normal
Ver arquivo

@@ -0,0 +1,397 @@
/* amr-wbplus audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/msm_audio_amrwbplus.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_amrwbplus_misc;
static struct ws_mgr audio_amrwbplus_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_amrwbplus_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
static void config_debug_fs(struct q6audio_aio *audio)
{
if (audio != NULL) {
char name[sizeof("msm_amrwbplus_") + 5];
snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_amrwbplus_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
}
}
#else
static void config_debug_fs(struct q6audio_aio *audio)
{
}
#endif
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
pr_err("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
amrwbplus_drv_config =
(struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
q6_amrwbplus_cfg.size_bytes =
amrwbplus_drv_config->size_bytes;
q6_amrwbplus_cfg.version =
amrwbplus_drv_config->version;
q6_amrwbplus_cfg.num_channels =
amrwbplus_drv_config->num_channels;
q6_amrwbplus_cfg.amr_band_mode =
amrwbplus_drv_config->amr_band_mode;
q6_amrwbplus_cfg.amr_dtx_mode =
amrwbplus_drv_config->amr_dtx_mode;
q6_amrwbplus_cfg.amr_frame_fmt =
amrwbplus_drv_config->amr_frame_fmt;
q6_amrwbplus_cfg.amr_lsf_idx =
amrwbplus_drv_config->amr_lsf_idx;
rc = q6asm_media_format_block_amrwbplus(audio->ac,
&q6_amrwbplus_cfg);
if (rc < 0) {
pr_err("q6asm_media_format_block_amrwb+ failed...\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
if ((audio) && (arg) && (audio->codec_cfg)) {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_amrwbplus_config_v2))) {
rc = -EFAULT;
pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2 failed\n",
__func__);
break;
}
} else {
pr_err("%s: wb+ config v2 invalid parameters\n"
, __func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
if ((audio) && (arg) && (audio->codec_cfg)) {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_amrwbplus_config_v2))) {
rc = -EFAULT;
pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2 failed\n",
__func__);
break;
}
} else {
pr_err("%s: wb+ config invalid parameters\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_amrwbplus_config_v2_32 {
u32 size_bytes;
u32 version;
u32 num_channels;
u32 amr_band_mode;
u32 amr_dtx_mode;
u32 amr_frame_fmt;
u32 amr_lsf_idx;
};
enum {
AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+2),
struct msm_audio_amrwbplus_config_v2_32),
AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+3),
struct msm_audio_amrwbplus_config_v2_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AMRWBPLUS_CONFIG_V2_32: {
if (audio && arg && (audio->codec_cfg)) {
struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
struct msm_audio_amrwbplus_config_v2_32
amrwbplus_config_32;
memset(&amrwbplus_config_32, 0,
sizeof(amrwbplus_config_32));
amrwbplus_config =
(struct msm_audio_amrwbplus_config_v2 *)
audio->codec_cfg;
amrwbplus_config_32.size_bytes =
amrwbplus_config->size_bytes;
amrwbplus_config_32.version =
amrwbplus_config->version;
amrwbplus_config_32.num_channels =
amrwbplus_config->num_channels;
amrwbplus_config_32.amr_band_mode =
amrwbplus_config->amr_band_mode;
amrwbplus_config_32.amr_dtx_mode =
amrwbplus_config->amr_dtx_mode;
amrwbplus_config_32.amr_frame_fmt =
amrwbplus_config->amr_frame_fmt;
amrwbplus_config_32.amr_lsf_idx =
amrwbplus_config->amr_lsf_idx;
if (copy_to_user((void *)arg, &amrwbplus_config_32,
sizeof(amrwbplus_config_32))) {
rc = -EFAULT;
pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 failed\n"
, __func__);
}
} else {
pr_err("%s: wb+ Get config v2 invalid parameters\n"
, __func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_AMRWBPLUS_CONFIG_V2_32: {
if ((audio) && (arg) && (audio->codec_cfg)) {
struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
struct msm_audio_amrwbplus_config_v2_32
amrwbplus_config_32;
if (copy_from_user(&amrwbplus_config_32, (void *)arg,
sizeof(struct msm_audio_amrwbplus_config_v2_32))) {
rc = -EFAULT;
pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 failed\n"
, __func__);
break;
}
amrwbplus_config =
(struct msm_audio_amrwbplus_config_v2 *)
audio->codec_cfg;
amrwbplus_config->size_bytes =
amrwbplus_config_32.size_bytes;
amrwbplus_config->version =
amrwbplus_config_32.version;
amrwbplus_config->num_channels =
amrwbplus_config_32.num_channels;
amrwbplus_config->amr_band_mode =
amrwbplus_config_32.amr_band_mode;
amrwbplus_config->amr_dtx_mode =
amrwbplus_config_32.amr_dtx_mode;
amrwbplus_config->amr_frame_fmt =
amrwbplus_config_32.amr_frame_fmt;
amrwbplus_config->amr_lsf_idx =
amrwbplus_config_32.amr_lsf_idx;
} else {
pr_err("%s: wb+ config invalid parameters\n",
__func__);
rc = -EFAULT;
}
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->codec_cfg =
kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_amrwbplus_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_amrwbplus_ws_mgr;
audio->ac =
q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_AMR_WB_PLUS);
if (rc < 0) {
pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
if (rc < 0) {
pr_err("wb+ T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("audio_amrwbplus Not supported mode\n");
rc = -EACCES;
goto fail;
}
config_debug_fs(audio);
pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_amrwbplus_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_amrwbplus_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amrwbplus",
.fops = &audio_amrwbplus_fops,
};
static int __init audio_amrwbplus_init(void)
{
int ret = misc_register(&audio_amrwbplus_misc);
if (ret == 0)
device_init_wakeup(audio_amrwbplus_misc.this_device, true);
audio_amrwbplus_ws_mgr.ref_cnt = 0;
mutex_init(&audio_amrwbplus_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_amrwbplus_init);

359
dsp/codecs/audio_ape.c Arquivo normal
Ver arquivo

@@ -0,0 +1,359 @@
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_ape.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_ape_misc;
static struct ws_mgr audio_ape_ws_mgr;
static const struct file_operations audio_ape_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
static struct dentry *config_debugfs_create_file(const char *name, void *data)
{
return debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)data, &audio_ape_debug_fops);
}
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_ape_cfg ape_cfg;
struct msm_audio_ape_config *ape_config;
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
ape_cfg.compatible_version = ape_config->compatibleVersion;
ape_cfg.compression_level = ape_config->compressionLevel;
ape_cfg.format_flags = ape_config->formatFlags;
ape_cfg.blocks_per_frame = ape_config->blocksPerFrame;
ape_cfg.final_frame_blocks = ape_config->finalFrameBlocks;
ape_cfg.total_frames = ape_config->totalFrames;
ape_cfg.bits_per_sample = ape_config->bitsPerSample;
ape_cfg.num_channels = ape_config->numChannels;
ape_cfg.sample_rate = ape_config->sampleRate;
ape_cfg.seek_table_present = ape_config->seekTablePresent;
pr_debug("%s: compatibleVersion %d compressionLevel %d formatFlags %d blocksPerFrame %d finalFrameBlocks %d totalFrames %d bitsPerSample %d numChannels %d sampleRate %d seekTablePresent %d\n",
__func__, ape_config->compatibleVersion,
ape_config->compressionLevel,
ape_config->formatFlags,
ape_config->blocksPerFrame,
ape_config->finalFrameBlocks,
ape_config->totalFrames,
ape_config->bitsPerSample,
ape_config->numChannels,
ape_config->sampleRate,
ape_config->seekTablePresent);
/* Configure Media format block */
rc = q6asm_media_format_block_ape(audio->ac, &ape_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_APE_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_ape_config))) {
pr_err("%s:copy_to_user for AUDIO_GET_APE_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_APE_CONFIG: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_ape_config))) {
pr_err("%s:copy_from_user for AUDIO_SET_APE_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_ape_config_32 {
u16 compatibleVersion;
u16 compressionLevel;
u32 formatFlags;
u32 blocksPerFrame;
u32 finalFrameBlocks;
u32 totalFrames;
u16 bitsPerSample;
u16 numChannels;
u32 sampleRate;
u32 seekTablePresent;
};
enum {
AUDIO_GET_APE_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_ape_config_32),
AUDIO_SET_APE_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_ape_config_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_APE_CONFIG_32: {
struct msm_audio_ape_config *ape_config;
struct msm_audio_ape_config_32 ape_config_32;
memset(&ape_config_32, 0, sizeof(ape_config_32));
ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
ape_config_32.compatibleVersion = ape_config->compatibleVersion;
ape_config_32.compressionLevel =
ape_config->compressionLevel;
ape_config_32.formatFlags = ape_config->formatFlags;
ape_config_32.blocksPerFrame = ape_config->blocksPerFrame;
ape_config_32.finalFrameBlocks = ape_config->finalFrameBlocks;
ape_config_32.totalFrames = ape_config->totalFrames;
ape_config_32.bitsPerSample = ape_config->bitsPerSample;
ape_config_32.numChannels = ape_config->numChannels;
ape_config_32.sampleRate = ape_config->sampleRate;
ape_config_32.seekTablePresent = ape_config->seekTablePresent;
if (copy_to_user((void *)arg, &ape_config_32,
sizeof(ape_config_32))) {
pr_err("%s: copy_to_user for GET_APE_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_APE_CONFIG_32: {
struct msm_audio_ape_config *ape_config;
struct msm_audio_ape_config_32 ape_config_32;
if (copy_from_user(&ape_config_32, (void *)arg,
sizeof(ape_config_32))) {
pr_err("%s: copy_from_user for SET_APE_CONFIG_32 failed\n"
, __func__);
rc = -EFAULT;
break;
}
ape_config = (struct msm_audio_ape_config *)audio->codec_cfg;
ape_config->compatibleVersion = ape_config_32.compatibleVersion;
ape_config->compressionLevel =
ape_config_32.compressionLevel;
ape_config->formatFlags = ape_config_32.formatFlags;
ape_config->blocksPerFrame = ape_config_32.blocksPerFrame;
ape_config->finalFrameBlocks = ape_config_32.finalFrameBlocks;
ape_config->totalFrames = ape_config_32.totalFrames;
ape_config->bitsPerSample = ape_config_32.bitsPerSample;
ape_config->numChannels = ape_config_32.numChannels;
ape_config->sampleRate = ape_config_32.sampleRate;
ape_config->seekTablePresent = ape_config_32.seekTablePresent;
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_ape_" + 5];
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (!audio)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_ape_config),
GFP_KERNEL);
if (!audio->codec_cfg) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_ape_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_ape_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_APE);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open APE decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_APE);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
snprintf(name, sizeof(name), "msm_ape_%04x", audio->ac->session);
audio->dentry = config_debugfs_create_file(name, (void *)audio);
if (IS_ERR_OR_NULL(audio->dentry))
pr_debug("debugfs_create_file failed\n");
pr_debug("%s:apedec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_ape_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_ape_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_ape",
.fops = &audio_ape_fops,
};
static int __init audio_ape_init(void)
{
int ret = misc_register(&audio_ape_misc);
if (ret == 0)
device_init_wakeup(audio_ape_misc.this_device, true);
audio_ape_ws_mgr.ref_cnt = 0;
mutex_init(&audio_ape_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_ape_init);

184
dsp/codecs/audio_evrc.c Arquivo normal
Ver arquivo

@@ -0,0 +1,184 @@
/* evrc audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "audio_utils_aio.h"
static struct miscdevice audio_evrc_misc;
static struct ws_mgr audio_evrc_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_evrc_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
}
return rc;
}
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_evrc_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_evrc_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_evrc_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_EVRC);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_EVRC);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_evrc_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_evrc_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio);
return rc;
}
static const struct file_operations audio_evrc_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
};
static struct miscdevice audio_evrc_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_evrc",
.fops = &audio_evrc_fops,
};
static int __init audio_evrc_init(void)
{
int ret = misc_register(&audio_evrc_misc);
if (ret == 0)
device_init_wakeup(audio_evrc_misc.this_device, true);
audio_evrc_ws_mgr.ref_cnt = 0;
mutex_init(&audio_evrc_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_evrc_init);

396
dsp/codecs/audio_g711alaw.c Arquivo normal
Ver arquivo

@@ -0,0 +1,396 @@
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_g711_dec.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_g711alaw_misc;
static struct ws_mgr audio_g711_ws_mgr;
static const struct file_operations audio_g711_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
static struct dentry *config_debugfs_create_file(const char *name, void *data)
{
return debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)data, &audio_g711_debug_fops);
}
static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_g711_dec_cfg g711_dec_cfg;
struct msm_audio_g711_dec_config *g711_dec_config;
u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
if (g711_channel_map(channel_mapping,
audio->pcm_cfg.channel_count)) {
pr_err("%s: setting channel map failed %d\n",
__func__, audio->pcm_cfg.channel_count);
}
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count,
16, /*bits per sample*/
false, false, channel_mapping);
if (rc < 0) {
pr_err("%s: pcm output block config failed rc=%d\n",
__func__, rc);
break;
}
}
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
/* Configure Media format block */
rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("%s: cmd media format block failed rc=%d\n",
__func__, rc);
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s: Audio Start procedure failed rc=%d\n",
__func__, rc);
break;
}
pr_debug("%s: AUDIO_START success enable[%d]\n",
__func__, audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_G711_DEC_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_g711_dec_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_DEC_CONFIG: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_g711_dec_config))) {
pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
default: {
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
__func__, rc, cmd);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_g711_dec_config_32 {
u32 sample_rate;
};
enum {
AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_G711_DEC_CONFIG_32: {
struct msm_audio_g711_dec_config *g711_dec_config;
struct msm_audio_g711_dec_config_32 g711_dec_config_32;
memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
if (copy_to_user((void *)arg, &g711_dec_config_32,
sizeof(g711_dec_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_DEC_CONFIG_32: {
struct msm_audio_g711_dec_config *g711_dec_config;
struct msm_audio_g711_dec_config_32 g711_dec_config_32;
memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
if (copy_from_user(&g711_dec_config_32, (void *)arg,
sizeof(g711_dec_config_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
break;
}
default: {
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
__func__, rc, cmd);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_g711_" + 5];
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (!audio)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
GFP_KERNEL);
if (!audio->codec_cfg) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_g711alaw_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_g711_ws_mgr;
init_waitqueue_head(&audio->event_wait);
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */ /*foramt:G711_ALAW*/
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_G711_ALAW_FS);
if (rc < 0) {
pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open G711 decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_G711_ALAW_FS);
if (rc < 0) {
pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("%s: %d mode is not supported mode\n",
__func__, file->f_mode);
rc = -EACCES;
goto fail;
}
snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
audio->dentry = config_debugfs_create_file(name, (void *)audio);
if (IS_ERR_OR_NULL(audio->dentry))
pr_debug("%s: debugfs_create_file failed\n", __func__);
pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
{
u8 *lchannel_mapping;
lchannel_mapping = channel_mapping;
pr_debug("%s: channels passed: %d\n", __func__, channels);
if (channels == 1) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
} else if (channels == 2) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
} else if (channels == 3) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
} else if (channels == 4) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_CS;
} else if (channels == 5) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
} else if (channels == 6) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_LFE;
} else if (channels == 7) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_CS;
lchannel_mapping[6] = PCM_CHANNEL_LFE;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FLC;
lchannel_mapping[2] = PCM_CHANNEL_FRC;
lchannel_mapping[3] = PCM_CHANNEL_FL;
lchannel_mapping[4] = PCM_CHANNEL_FR;
lchannel_mapping[5] = PCM_CHANNEL_LS;
lchannel_mapping[6] = PCM_CHANNEL_RS;
lchannel_mapping[7] = PCM_CHANNEL_LFE;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
return -EINVAL;
}
return 0;
}
static const struct file_operations audio_g711_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.compat_ioctl = audio_compat_ioctl,
.fsync = audio_aio_fsync,
};
static struct miscdevice audio_g711alaw_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_g711alaw",
.fops = &audio_g711_fops,
};
static int __init audio_g711alaw_init(void)
{
int ret = misc_register(&audio_g711alaw_misc);
if (ret == 0)
device_init_wakeup(audio_g711alaw_misc.this_device, true);
audio_g711_ws_mgr.ref_cnt = 0;
mutex_init(&audio_g711_ws_mgr.ws_lock);
return ret;
}
static void __exit audio_g711alaw_exit(void)
{
misc_deregister(&audio_g711alaw_misc);
mutex_destroy(&audio_g711_ws_mgr.ws_lock);
}
device_initcall(audio_g711alaw_init);
__exitcall(audio_g711alaw_exit);

396
dsp/codecs/audio_g711mlaw.c Arquivo normal
Ver arquivo

@@ -0,0 +1,396 @@
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_g711_dec.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_g711mlaw_misc;
static struct ws_mgr audio_g711_ws_mgr;
static const struct file_operations audio_g711_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
static struct dentry *config_debugfs_create_file(const char *name, void *data)
{
return debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)data, &audio_g711_debug_fops);
}
static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_g711_dec_cfg g711_dec_cfg;
struct msm_audio_g711_dec_config *g711_dec_config;
u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
if (g711_channel_map(channel_mapping,
audio->pcm_cfg.channel_count)) {
pr_err("%s: setting channel map failed %d\n",
__func__, audio->pcm_cfg.channel_count);
}
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count,
16, /*bits per sample*/
false, false, channel_mapping);
if (rc < 0) {
pr_err("%s: pcm output block config failed rc=%d\n",
__func__, rc);
break;
}
}
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
/* Configure Media format block */
rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("%s: cmd media format block failed rc=%d\n",
__func__, rc);
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s: Audio Start procedure failed rc=%d\n",
__func__, rc);
break;
}
pr_debug("%s: AUDIO_START success enable[%d]\n",
__func__, audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_G711_DEC_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_g711_dec_config))) {
pr_err("%s: AUDIO_GET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_DEC_CONFIG: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_g711_dec_config))) {
pr_err("%s: AUDIO_SET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
default: {
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
__func__, rc, cmd);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_g711_dec_config_32 {
u32 sample_rate;
};
enum {
AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_G711_DEC_CONFIG_32: {
struct msm_audio_g711_dec_config *g711_dec_config;
struct msm_audio_g711_dec_config_32 g711_dec_config_32;
memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
if (copy_to_user((void *)arg, &g711_dec_config_32,
sizeof(g711_dec_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_DEC_CONFIG_32: {
struct msm_audio_g711_dec_config *g711_dec_config;
struct msm_audio_g711_dec_config_32 g711_dec_config_32;
memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
if (copy_from_user(&g711_dec_config_32, (void *)arg,
sizeof(g711_dec_config_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
g711_dec_config =
(struct msm_audio_g711_dec_config *)audio->codec_cfg;
g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
break;
}
default: {
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
__func__, rc, cmd);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_g711_" + 5];
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (!audio)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
GFP_KERNEL);
if (!audio->codec_cfg) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_g711mlaw_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_g711_ws_mgr;
init_waitqueue_head(&audio->event_wait);
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */ /*foramt:G711_ALAW*/
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_G711_MLAW_FS);
if (rc < 0) {
pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open G711 decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_G711_MLAW_FS);
if (rc < 0) {
pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("%s: %d mode is not supported\n", __func__,
file->f_mode);
rc = -EACCES;
goto fail;
}
snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
audio->dentry = config_debugfs_create_file(name, (void *)audio);
if (IS_ERR_OR_NULL(audio->dentry))
pr_debug("%s: debugfs_create_file failed\n", __func__);
pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
{
u8 *lchannel_mapping;
lchannel_mapping = channel_mapping;
pr_debug("%s: channels passed: %d\n", __func__, channels);
if (channels == 1) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
} else if (channels == 2) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
} else if (channels == 3) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
} else if (channels == 4) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_CS;
} else if (channels == 5) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
} else if (channels == 6) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_LFE;
} else if (channels == 7) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FL;
lchannel_mapping[2] = PCM_CHANNEL_FR;
lchannel_mapping[3] = PCM_CHANNEL_LS;
lchannel_mapping[4] = PCM_CHANNEL_RS;
lchannel_mapping[5] = PCM_CHANNEL_CS;
lchannel_mapping[6] = PCM_CHANNEL_LFE;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FC;
lchannel_mapping[1] = PCM_CHANNEL_FLC;
lchannel_mapping[2] = PCM_CHANNEL_FRC;
lchannel_mapping[3] = PCM_CHANNEL_FL;
lchannel_mapping[4] = PCM_CHANNEL_FR;
lchannel_mapping[5] = PCM_CHANNEL_LS;
lchannel_mapping[6] = PCM_CHANNEL_RS;
lchannel_mapping[7] = PCM_CHANNEL_LFE;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
return -EINVAL;
}
return 0;
}
static const struct file_operations audio_g711_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.compat_ioctl = audio_compat_ioctl,
.fsync = audio_aio_fsync,
};
static struct miscdevice audio_g711mlaw_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_g711mlaw",
.fops = &audio_g711_fops,
};
static int __init audio_g711mlaw_init(void)
{
int ret = misc_register(&audio_g711mlaw_misc);
if (ret == 0)
device_init_wakeup(audio_g711mlaw_misc.this_device, true);
audio_g711_ws_mgr.ref_cnt = 0;
mutex_init(&audio_g711_ws_mgr.ws_lock);
return ret;
}
static void __exit audio_g711mlaw_exit(void)
{
misc_deregister(&audio_g711mlaw_misc);
mutex_destroy(&audio_g711_ws_mgr.ws_lock);
}
device_initcall(audio_g711mlaw_init);
__exitcall(audio_g711mlaw_exit);

Ver arquivo

@@ -0,0 +1,778 @@
/*
* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/msm_audio.h>
#include <linux/compat.h>
#include "q6audio_common.h"
#include <dsp/msm-audio-effects-q6-v2.h>
#include "audio_utils_aio.h"
#define MAX_CHANNELS_SUPPORTED 8
#define WAIT_TIMEDOUT_DURATION_SECS 1
struct q6audio_effects {
wait_queue_head_t read_wait;
wait_queue_head_t write_wait;
struct audio_client *ac;
struct msm_hwacc_effects_config config;
struct mutex lock;
atomic_t in_count;
atomic_t out_count;
int opened;
int started;
int buf_alloc;
struct msm_nt_eff_all_config audio_effects;
};
static void audio_effects_init_pp(struct audio_client *ac)
{
int ret = 0;
struct asm_softvolume_params softvol = {
.period = SOFT_VOLUME_PERIOD,
.step = SOFT_VOLUME_STEP,
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
if (!ac) {
pr_err("%s: audio client null to init pp\n", __func__);
return;
}
ret = q6asm_set_softvolume_v2(ac, &softvol,
SOFT_VOLUME_INSTANCE_1);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
}
static void audio_effects_deinit_pp(struct audio_client *ac)
{
if (!ac) {
pr_err("%s: audio client null to deinit pp\n", __func__);
return;
}
}
static void audio_effects_event_handler(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
struct q6audio_effects *effects;
if (!payload || !priv) {
pr_err("%s: invalid data to handle events, payload: %pK, priv: %pK\n",
__func__, payload, priv);
return;
}
effects = (struct q6audio_effects *)priv;
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2: {
atomic_inc(&effects->out_count);
wake_up(&effects->write_wait);
break;
}
case ASM_DATA_EVENT_READ_DONE_V2: {
atomic_inc(&effects->in_count);
wake_up(&effects->read_wait);
break;
}
case APR_BASIC_RSP_RESULT: {
pr_debug("%s: APR_BASIC_RSP_RESULT Cmd[0x%x] Status[0x%x]\n",
__func__, payload[0], payload[1]);
switch (payload[0]) {
case ASM_SESSION_CMD_RUN_V2:
pr_debug("ASM_SESSION_CMD_RUN_V2\n");
break;
default:
pr_debug("%s: Payload = [0x%x] stat[0x%x]\n",
__func__, payload[0], payload[1]);
break;
}
break;
}
default:
pr_debug("%s: Unhandled Event 0x%x token = 0x%x\n",
__func__, opcode, token);
break;
}
}
static int audio_effects_shared_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_effects *effects = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s: AUDIO_START\n", __func__);
mutex_lock(&effects->lock);
rc = q6asm_open_read_write_v2(effects->ac,
FORMAT_LINEAR_PCM,
FORMAT_MULTI_CHANNEL_LINEAR_PCM,
effects->config.meta_mode_enabled,
effects->config.output.bits_per_sample,
true /*overwrite topology*/,
ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER);
if (rc < 0) {
pr_err("%s: Open failed for hw accelerated effects:rc=%d\n",
__func__, rc);
rc = -EINVAL;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
effects->opened = 1;
pr_debug("%s: dec buf size: %d, num_buf: %d, enc buf size: %d, num_buf: %d\n",
__func__, effects->config.output.buf_size,
effects->config.output.num_buf,
effects->config.input.buf_size,
effects->config.input.num_buf);
rc = q6asm_audio_client_buf_alloc_contiguous(IN, effects->ac,
effects->config.output.buf_size,
effects->config.output.num_buf);
if (rc < 0) {
pr_err("%s: Write buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_set(&effects->in_count, effects->config.input.num_buf);
rc = q6asm_audio_client_buf_alloc_contiguous(OUT, effects->ac,
effects->config.input.buf_size,
effects->config.input.num_buf);
if (rc < 0) {
pr_err("%s: Read buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
mutex_unlock(&effects->lock);
goto readbuf_fail;
}
atomic_set(&effects->out_count, effects->config.output.num_buf);
effects->buf_alloc = 1;
pr_debug("%s: enc: sample_rate: %d, num_channels: %d\n",
__func__, effects->config.input.sample_rate,
effects->config.input.num_channels);
rc = q6asm_enc_cfg_blk_pcm(effects->ac,
effects->config.input.sample_rate,
effects->config.input.num_channels);
if (rc < 0) {
pr_err("%s: pcm read block config failed\n", __func__);
rc = -EINVAL;
mutex_unlock(&effects->lock);
goto cfg_fail;
}
pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n",
__func__, effects->config.output.sample_rate,
effects->config.output.num_channels,
effects->config.output.bits_per_sample);
rc = q6asm_media_format_block_pcm_format_support(
effects->ac, effects->config.output.sample_rate,
effects->config.output.num_channels,
effects->config.output.bits_per_sample);
if (rc < 0) {
pr_err("%s: pcm write format block config failed\n",
__func__);
rc = -EINVAL;
mutex_unlock(&effects->lock);
goto cfg_fail;
}
audio_effects_init_pp(effects->ac);
rc = q6asm_run(effects->ac, 0x00, 0x00, 0x00);
if (!rc)
effects->started = 1;
else {
effects->started = 0;
pr_err("%s: ASM run state failed\n", __func__);
}
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_WRITE: {
char *bufptr = NULL;
uint32_t idx = 0;
uint32_t size = 0;
mutex_lock(&effects->lock);
if (!effects->started) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
rc = wait_event_timeout(effects->write_wait,
atomic_read(&effects->out_count),
WAIT_TIMEDOUT_DURATION_SECS * HZ);
if (!rc) {
pr_err("%s: write wait_event_timeout\n", __func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->out_count)) {
pr_err("%s: pcm stopped out_count 0\n", __func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
bufptr = q6asm_is_cpu_buf_avail(IN, effects->ac, &size, &idx);
if (bufptr) {
if ((effects->config.buf_cfg.output_len > size) ||
copy_from_user(bufptr, (void *)arg,
effects->config.buf_cfg.output_len)) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
rc = q6asm_write(effects->ac,
effects->config.buf_cfg.output_len,
0, 0, NO_TIMESTAMP);
if (rc < 0) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_dec(&effects->out_count);
} else {
pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n",
__func__);
}
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_READ: {
char *bufptr = NULL;
uint32_t idx = 0;
uint32_t size = 0;
mutex_lock(&effects->lock);
if (!effects->started) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_set(&effects->in_count, 0);
q6asm_read_v2(effects->ac, effects->config.buf_cfg.input_len);
/* Read might fail initially, don't error out */
if (rc < 0)
pr_err("%s: read failed\n", __func__);
rc = wait_event_timeout(effects->read_wait,
atomic_read(&effects->in_count),
WAIT_TIMEDOUT_DURATION_SECS * HZ);
if (!rc) {
pr_err("%s: read wait_event_timeout\n", __func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->in_count)) {
pr_err("%s: pcm stopped in_count 0\n", __func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
bufptr = q6asm_is_cpu_buf_avail(OUT, effects->ac, &size, &idx);
if (bufptr) {
if (!((void *)arg)) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if ((effects->config.buf_cfg.input_len > size) ||
copy_to_user((void *)arg, bufptr,
effects->config.buf_cfg.input_len)) {
rc = -EFAULT;
mutex_unlock(&effects->lock);
goto ioctl_fail;
}
}
mutex_unlock(&effects->lock);
break;
}
default:
pr_err("%s: Invalid effects config module\n", __func__);
rc = -EINVAL;
break;
}
ioctl_fail:
return rc;
readbuf_fail:
q6asm_audio_client_buf_free_contiguous(IN,
effects->ac);
return rc;
cfg_fail:
q6asm_audio_client_buf_free_contiguous(IN,
effects->ac);
q6asm_audio_client_buf_free_contiguous(OUT,
effects->ac);
effects->buf_alloc = 0;
return rc;
}
static long audio_effects_set_pp_param(struct q6audio_effects *effects,
long *values)
{
int rc = 0;
int effects_module = values[0];
switch (effects_module) {
case VIRTUALIZER_MODULE:
pr_debug("%s: VIRTUALIZER_MODULE\n", __func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_virtualizer_handler(
effects->ac,
&(effects->audio_effects.virtualizer),
(long *)&values[1]);
break;
case REVERB_MODULE:
pr_debug("%s: REVERB_MODULE\n", __func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_reverb_handler(effects->ac,
&(effects->audio_effects.reverb),
(long *)&values[1]);
break;
case BASS_BOOST_MODULE:
pr_debug("%s: BASS_BOOST_MODULE\n", __func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_bass_boost_handler(
effects->ac,
&(effects->audio_effects.bass_boost),
(long *)&values[1]);
break;
case PBE_MODULE:
pr_debug("%s: PBE_MODULE\n", __func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_pbe_handler(
effects->ac,
&(effects->audio_effects.pbe),
(long *)&values[1]);
break;
case EQ_MODULE:
pr_debug("%s: EQ_MODULE\n", __func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_popless_eq_handler(
effects->ac,
&(effects->audio_effects.equalizer),
(long *)&values[1]);
break;
case SOFT_VOLUME_MODULE:
pr_debug("%s: SA PLUS VOLUME_MODULE\n", __func__);
msm_audio_effects_volume_handler_v2(effects->ac,
&(effects->audio_effects.saplus_vol),
(long *)&values[1], SOFT_VOLUME_INSTANCE_1);
break;
case SOFT_VOLUME2_MODULE:
pr_debug("%s: TOPOLOGY SWITCH VOLUME MODULE\n",
__func__);
if (msm_audio_effects_is_effmodule_supp_in_top(
effects_module, effects->ac->topology))
msm_audio_effects_volume_handler_v2(effects->ac,
&(effects->audio_effects.topo_switch_vol),
(long *)&values[1], SOFT_VOLUME_INSTANCE_2);
break;
default:
pr_err("%s: Invalid effects config module\n", __func__);
rc = -EINVAL;
}
return rc;
}
static long audio_effects_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_effects *effects = file->private_data;
int rc = 0;
long argvalues[MAX_PP_PARAMS_SZ] = {0};
switch (cmd) {
case AUDIO_SET_EFFECTS_CONFIG: {
pr_debug("%s: AUDIO_SET_EFFECTS_CONFIG\n", __func__);
mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&effects->config, (void *)arg,
sizeof(effects->config))) {
pr_err("%s: copy from user for AUDIO_SET_EFFECTS_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
pr_debug("%s: write buf_size: %d, num_buf: %d, sample_rate: %d, channel: %d\n",
__func__, effects->config.output.buf_size,
effects->config.output.num_buf,
effects->config.output.sample_rate,
effects->config.output.num_channels);
pr_debug("%s: read buf_size: %d, num_buf: %d, sample_rate: %d, channel: %d\n",
__func__, effects->config.input.buf_size,
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN: {
mutex_lock(&effects->lock);
if (copy_from_user(&effects->config.buf_cfg, (void *)arg,
sizeof(effects->config.buf_cfg))) {
pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
__func__);
rc = -EFAULT;
}
pr_debug("%s: write buf len: %d, read buf len: %d\n",
__func__, effects->config.buf_cfg.output_len,
effects->config.buf_cfg.input_len);
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL: {
struct msm_hwacc_buf_avail buf_avail;
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
mutex_lock(&effects->lock);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
__func__, buf_avail.output_num_avail,
buf_avail.input_num_avail);
if (copy_to_user((void *)arg, &buf_avail,
sizeof(buf_avail))) {
pr_err("%s: copy to user for AUDIO_EFFECTS_GET_NUM_BUF_AVAIL failed\n",
__func__);
rc = -EFAULT;
}
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS: {
mutex_lock(&effects->lock);
if (copy_from_user(argvalues, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(long))) {
pr_err("%s: copy from user for pp params failed\n",
__func__);
mutex_unlock(&effects->lock);
return -EFAULT;
}
rc = audio_effects_set_pp_param(effects, argvalues);
mutex_unlock(&effects->lock);
break;
}
default:
pr_debug("%s: Calling shared ioctl\n", __func__);
rc = audio_effects_shared_ioctl(file, cmd, arg);
break;
}
if (rc)
pr_err("%s: cmd 0x%x failed\n", __func__, cmd);
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_hwacc_data_config32 {
__u32 buf_size;
__u32 num_buf;
__u32 num_channels;
__u8 channel_map[MAX_CHANNELS_SUPPORTED];
__u32 sample_rate;
__u32 bits_per_sample;
};
struct msm_hwacc_buf_cfg32 {
__u32 input_len;
__u32 output_len;
};
struct msm_hwacc_buf_avail32 {
__u32 input_num_avail;
__u32 output_num_avail;
};
struct msm_hwacc_effects_config32 {
struct msm_hwacc_data_config32 input;
struct msm_hwacc_data_config32 output;
struct msm_hwacc_buf_cfg32 buf_cfg;
__u32 meta_mode_enabled;
__u32 overwrite_topology;
__s32 topology;
};
enum {
AUDIO_SET_EFFECTS_CONFIG32 = _IOW(AUDIO_IOCTL_MAGIC, 99,
struct msm_hwacc_effects_config32),
AUDIO_EFFECTS_SET_BUF_LEN32 = _IOW(AUDIO_IOCTL_MAGIC, 100,
struct msm_hwacc_buf_cfg32),
AUDIO_EFFECTS_GET_BUF_AVAIL32 = _IOW(AUDIO_IOCTL_MAGIC, 101,
struct msm_hwacc_buf_avail32),
AUDIO_EFFECTS_WRITE32 = _IOW(AUDIO_IOCTL_MAGIC, 102, compat_uptr_t),
AUDIO_EFFECTS_READ32 = _IOWR(AUDIO_IOCTL_MAGIC, 103, compat_uptr_t),
AUDIO_EFFECTS_SET_PP_PARAMS32 = _IOW(AUDIO_IOCTL_MAGIC, 104,
compat_uptr_t),
AUDIO_START32 = _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned int),
};
static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_effects *effects = file->private_data;
int rc = 0, i;
switch (cmd) {
case AUDIO_SET_EFFECTS_CONFIG32: {
struct msm_hwacc_effects_config32 config32;
struct msm_hwacc_effects_config *config = &effects->config;
mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&config32, (void *)arg,
sizeof(config32))) {
pr_err("%s: copy to user for AUDIO_SET_EFFECTS_CONFIG failed\n",
__func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
break;
}
config->input.buf_size = config32.input.buf_size;
config->input.num_buf = config32.input.num_buf;
config->input.num_channels = config32.input.num_channels;
config->input.sample_rate = config32.input.sample_rate;
config->input.bits_per_sample = config32.input.bits_per_sample;
config->input.buf_size = config32.input.buf_size;
for (i = 0; i < MAX_CHANNELS_SUPPORTED; i++)
config->input.channel_map[i] =
config32.input.channel_map[i];
config->output.buf_size = config32.output.buf_size;
config->output.num_buf = config32.output.num_buf;
config->output.num_channels = config32.output.num_channels;
config->output.sample_rate = config32.output.sample_rate;
config->output.bits_per_sample =
config32.output.bits_per_sample;
config->output.buf_size = config32.output.buf_size;
for (i = 0; i < MAX_CHANNELS_SUPPORTED; i++)
config->output.channel_map[i] =
config32.output.channel_map[i];
config->buf_cfg.input_len = config32.buf_cfg.input_len;
config->buf_cfg.output_len = config32.buf_cfg.output_len;
config->meta_mode_enabled = config32.meta_mode_enabled;
config->overwrite_topology = config32.overwrite_topology;
config->topology = config32.topology;
pr_debug("%s: write buf_size: %d, num_buf: %d, sample_rate: %d, channels: %d\n",
__func__, effects->config.output.buf_size,
effects->config.output.num_buf,
effects->config.output.sample_rate,
effects->config.output.num_channels);
pr_debug("%s: read buf_size: %d, num_buf: %d, sample_rate: %d, channels: %d\n",
__func__, effects->config.input.buf_size,
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN32: {
struct msm_hwacc_buf_cfg32 buf_cfg32;
struct msm_hwacc_effects_config *config = &effects->config;
mutex_lock(&effects->lock);
if (copy_from_user(&buf_cfg32, (void *)arg,
sizeof(buf_cfg32))) {
pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
__func__);
rc = -EFAULT;
mutex_unlock(&effects->lock);
break;
}
config->buf_cfg.input_len = buf_cfg32.input_len;
config->buf_cfg.output_len = buf_cfg32.output_len;
pr_debug("%s: write buf len: %d, read buf len: %d\n",
__func__, effects->config.buf_cfg.output_len,
effects->config.buf_cfg.input_len);
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL32: {
struct msm_hwacc_buf_avail32 buf_avail;
memset(&buf_avail, 0, sizeof(buf_avail));
mutex_lock(&effects->lock);
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
__func__, buf_avail.output_num_avail,
buf_avail.input_num_avail);
if (copy_to_user((void *)arg, &buf_avail,
sizeof(buf_avail))) {
pr_err("%s: copy to user for AUDIO_EFFECTS_GET_NUM_BUF_AVAIL failed\n",
__func__);
rc = -EFAULT;
}
mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS32: {
long argvalues[MAX_PP_PARAMS_SZ] = {0};
int argvalues32[MAX_PP_PARAMS_SZ] = {0};
mutex_lock(&effects->lock);
if (copy_from_user(argvalues32, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(int))) {
pr_err("%s: copy from user failed for pp params\n",
__func__);
mutex_unlock(&effects->lock);
return -EFAULT;
}
for (i = 0; i < MAX_PP_PARAMS_SZ; i++)
argvalues[i] = argvalues32[i];
rc = audio_effects_set_pp_param(effects, argvalues);
mutex_unlock(&effects->lock);
break;
}
case AUDIO_START32: {
rc = audio_effects_shared_ioctl(file, AUDIO_START, arg);
break;
}
case AUDIO_EFFECTS_WRITE32: {
rc = audio_effects_shared_ioctl(file, AUDIO_EFFECTS_WRITE, arg);
break;
}
case AUDIO_EFFECTS_READ32: {
rc = audio_effects_shared_ioctl(file, AUDIO_EFFECTS_READ, arg);
break;
}
default:
pr_debug("%s: unhandled ioctl\n", __func__);
rc = -EINVAL;
break;
}
return rc;
}
#endif
static int audio_effects_release(struct inode *inode, struct file *file)
{
struct q6audio_effects *effects = file->private_data;
int rc = 0;
if (!effects) {
pr_err("%s: effect is NULL\n", __func__);
return -EINVAL;
}
if (effects->opened) {
rc = wait_event_timeout(effects->write_wait,
atomic_read(&effects->out_count),
WAIT_TIMEDOUT_DURATION_SECS * HZ);
if (!rc)
pr_err("%s: write wait_event_timeout failed\n",
__func__);
rc = wait_event_timeout(effects->read_wait,
atomic_read(&effects->in_count),
WAIT_TIMEDOUT_DURATION_SECS * HZ);
if (!rc)
pr_err("%s: read wait_event_timeout failed\n",
__func__);
rc = q6asm_cmd(effects->ac, CMD_CLOSE);
if (rc < 0)
pr_err("%s[%pK]:Failed to close the session rc=%d\n",
__func__, effects, rc);
effects->opened = 0;
effects->started = 0;
audio_effects_deinit_pp(effects->ac);
}
if (effects->buf_alloc) {
q6asm_audio_client_buf_free_contiguous(IN, effects->ac);
q6asm_audio_client_buf_free_contiguous(OUT, effects->ac);
}
q6asm_audio_client_free(effects->ac);
mutex_destroy(&effects->lock);
kfree(effects);
pr_debug("%s: close session success\n", __func__);
return rc;
}
static int audio_effects_open(struct inode *inode, struct file *file)
{
struct q6audio_effects *effects;
int rc = 0;
effects = kzalloc(sizeof(struct q6audio_effects), GFP_KERNEL);
if (!effects)
return -ENOMEM;
effects->ac = q6asm_audio_client_alloc(
(app_cb)audio_effects_event_handler,
(void *)effects);
if (!effects->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(effects);
return -ENOMEM;
}
init_waitqueue_head(&effects->read_wait);
init_waitqueue_head(&effects->write_wait);
mutex_init(&effects->lock);
effects->opened = 0;
effects->started = 0;
effects->buf_alloc = 0;
file->private_data = effects;
pr_debug("%s: open session success\n", __func__);
return rc;
}
static const struct file_operations audio_effects_fops = {
.owner = THIS_MODULE,
.open = audio_effects_open,
.release = audio_effects_release,
.unlocked_ioctl = audio_effects_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = audio_effects_compat_ioctl,
#endif
};
struct miscdevice audio_effects_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_hweffects",
.fops = &audio_effects_fops,
};
static int __init audio_effects_init(void)
{
return misc_register(&audio_effects_misc);
}
device_initcall(audio_effects_init);
MODULE_DESCRIPTION("Audio hardware accelerated effects driver");
MODULE_LICENSE("GPL v2");

188
dsp/codecs/audio_mp3.c Arquivo normal
Ver arquivo

@@ -0,0 +1,188 @@
/* mp3 audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "audio_utils_aio.h"
static struct miscdevice audio_mp3_misc;
static struct ws_mgr audio_mp3_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_mp3_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
rc = enable_volume_ramp(audio);
if (rc < 0) {
pr_err("%s: Failed to enable volume ramp\n",
__func__);
}
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
}
return rc;
}
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_mp3_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_mp3_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_mp3_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_MP3);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open MP3 decoder, expected frames is always 1
* audio->buf_cfg.frames_per_buf = 0x01;
*/
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_MP3);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_mp3_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_mp3_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:mp3dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio);
return rc;
}
static const struct file_operations audio_mp3_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
};
static struct miscdevice audio_mp3_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_mp3",
.fops = &audio_mp3_fops,
};
static int __init audio_mp3_init(void)
{
int ret = misc_register(&audio_mp3_misc);
if (ret == 0)
device_init_wakeup(audio_mp3_misc.this_device, true);
audio_mp3_ws_mgr.ref_cnt = 0;
mutex_init(&audio_mp3_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_mp3_init);

523
dsp/codecs/audio_multi_aac.c Arquivo normal
Ver arquivo

@@ -0,0 +1,523 @@
/* aac audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/msm_audio_aac.h>
#include <linux/compat.h>
#include <soc/qcom/socinfo.h>
#include "audio_utils_aio.h"
#define AUDIO_AAC_DUAL_MONO_INVALID -1
/* Default number of pre-allocated event packets */
#define PCM_BUFSZ_MIN_AACM ((8*1024) + sizeof(struct dec_meta_out))
static struct miscdevice audio_multiaac_misc;
static struct ws_mgr audio_multiaac_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_aac_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_aac_cfg aac_cfg;
struct msm_audio_aac_config *aac_config;
uint32_t sbr_ps = 0x00;
aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
if (audio->feedback == TUNNEL_MODE) {
aac_cfg.sample_rate = aac_config->sample_rate;
aac_cfg.ch_cfg = aac_config->channel_configuration;
} else {
aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
}
pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm_native(audio->ac,
aac_cfg.sample_rate,
aac_cfg.ch_cfg);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
/* turn on both sbr and ps */
rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
if (rc < 0)
pr_err("sbr-ps enable failed\n");
if (aac_config->sbr_ps_on_flag)
aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
else if (aac_config->sbr_on_flag)
aac_cfg.aot = AAC_ENC_MODE_AAC_P;
else
aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
switch (aac_config->format) {
case AUDIO_AAC_FORMAT_ADTS:
aac_cfg.format = 0x00;
break;
case AUDIO_AAC_FORMAT_LOAS:
aac_cfg.format = 0x01;
break;
case AUDIO_AAC_FORMAT_ADIF:
aac_cfg.format = 0x02;
break;
default:
case AUDIO_AAC_FORMAT_RAW:
aac_cfg.format = 0x03;
}
aac_cfg.ep_config = aac_config->ep_config;
aac_cfg.section_data_resilience =
aac_config->aac_section_data_resilience_flag;
aac_cfg.scalefactor_data_resilience =
aac_config->aac_scalefactor_data_resilience_flag;
aac_cfg.spectral_data_resilience =
aac_config->aac_spectral_data_resilience_flag;
pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
__func__, aac_cfg.format,
aac_cfg.aot, aac_cfg.ch_cfg,
aac_cfg.sample_rate);
/* Configure Media format block */
rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = q6asm_set_encdec_chan_map(audio->ac, 2);
if (rc < 0) {
pr_err("%s: cmd set encdec_chan_map failed\n",
__func__);
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config *aac_config;
uint16_t sce_left = 1, sce_right = 2;
if (arg == NULL) {
pr_err("%s: NULL config pointer\n", __func__);
rc = -EINVAL;
break;
}
memcpy(audio->codec_cfg, arg,
sizeof(struct msm_audio_aac_config));
aac_config = audio->codec_cfg;
if (aac_config->dual_mono_mode >
AUDIO_AAC_DUAL_MONO_PL_SR) {
pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
__func__, aac_config->dual_mono_mode);
} else {
/* convert the data from user into sce_left
* and sce_right based on the definitions
*/
pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
__func__, aac_config->dual_mono_mode);
switch (aac_config->dual_mono_mode) {
case AUDIO_AAC_DUAL_MONO_PL_PR:
sce_left = 1;
sce_right = 1;
break;
case AUDIO_AAC_DUAL_MONO_SL_SR:
sce_left = 2;
sce_right = 2;
break;
case AUDIO_AAC_DUAL_MONO_SL_PR:
sce_left = 2;
sce_right = 1;
break;
case AUDIO_AAC_DUAL_MONO_PL_SR:
default:
sce_left = 1;
sce_right = 2;
break;
}
rc = q6asm_cfg_dual_mono_aac(audio->ac,
sce_left, sce_right);
if (rc < 0)
pr_err("%s: asm cmd dualmono failed rc=%d\n",
__func__, rc);
} break;
break;
}
case AUDIO_SET_AAC_MIX_CONFIG: {
u32 *mix_coeff = (u32 *)arg;
if (!arg) {
pr_err("%s: Invalid param for %s\n",
__func__, "AUDIO_SET_AAC_MIX_CONFIG");
rc = -EINVAL;
break;
}
pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__);
pr_debug("%s, value of coeff = %d",
__func__, *mix_coeff);
q6asm_cfg_aac_sel_mix_coef(audio->ac, *mix_coeff);
if (rc < 0)
pr_err("%s asm aac_sel_mix_coef failed rc=%d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AAC_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_aac_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG failed\n"
, __func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG: {
struct msm_audio_aac_config aac_config;
if (copy_from_user(&aac_config, (void *)arg,
sizeof(aac_config))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_CONFIG failed\n"
, __func__);
rc = -EFAULT;
}
rc = audio_ioctl_shared(file, cmd, &aac_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
case AUDIO_SET_AAC_MIX_CONFIG: {
u32 mix_config;
pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__);
if (copy_from_user(&mix_config, (void *)arg,
sizeof(u32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_MIX_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = audio_ioctl_shared(file, cmd, &mix_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default: {
pr_debug("Calling utils ioctl\n");
rc = audio->codec_ioctl(file, cmd, arg);
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_aac_config32 {
s16 format;
u16 audio_object;
u16 ep_config; /* 0 ~ 3 useful only obj = ERLC */
u16 aac_section_data_resilience_flag;
u16 aac_scalefactor_data_resilience_flag;
u16 aac_spectral_data_resilience_flag;
u16 sbr_on_flag;
u16 sbr_ps_on_flag;
u16 dual_mono_mode;
u16 channel_configuration;
u16 sample_rate;
};
enum {
AUDIO_SET_AAC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_aac_config32),
AUDIO_GET_AAC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_aac_config32),
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_AAC_CONFIG_32: {
struct msm_audio_aac_config *aac_config;
struct msm_audio_aac_config32 aac_config_32;
memset(&aac_config_32, 0, sizeof(aac_config_32));
aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
aac_config_32.format = aac_config->format;
aac_config_32.audio_object = aac_config->audio_object;
aac_config_32.ep_config = aac_config->ep_config;
aac_config_32.aac_section_data_resilience_flag =
aac_config->aac_section_data_resilience_flag;
aac_config_32.aac_scalefactor_data_resilience_flag =
aac_config->aac_scalefactor_data_resilience_flag;
aac_config_32.aac_spectral_data_resilience_flag =
aac_config->aac_spectral_data_resilience_flag;
aac_config_32.sbr_on_flag = aac_config->sbr_on_flag;
aac_config_32.sbr_ps_on_flag = aac_config->sbr_ps_on_flag;
aac_config_32.dual_mono_mode = aac_config->dual_mono_mode;
aac_config_32.channel_configuration =
aac_config->channel_configuration;
aac_config_32.sample_rate = aac_config->sample_rate;
if (copy_to_user((void *)arg, &aac_config_32,
sizeof(aac_config_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_AAC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_AAC_CONFIG_32: {
struct msm_audio_aac_config aac_config;
struct msm_audio_aac_config32 aac_config_32;
pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
if (copy_from_user(&aac_config_32, (void *)arg,
sizeof(aac_config_32))) {
pr_err(
"%s: copy_from_user for AUDIO_SET_AAC_CONFIG_32 failed",
__func__);
rc = -EFAULT;
break;
}
aac_config.format = aac_config_32.format;
aac_config.audio_object = aac_config_32.audio_object;
aac_config.ep_config = aac_config_32.ep_config;
aac_config.aac_section_data_resilience_flag =
aac_config_32.aac_section_data_resilience_flag;
aac_config.aac_scalefactor_data_resilience_flag =
aac_config_32.aac_scalefactor_data_resilience_flag;
aac_config.aac_spectral_data_resilience_flag =
aac_config_32.aac_spectral_data_resilience_flag;
aac_config.sbr_on_flag = aac_config_32.sbr_on_flag;
aac_config.sbr_ps_on_flag = aac_config_32.sbr_ps_on_flag;
aac_config.dual_mono_mode = aac_config_32.dual_mono_mode;
aac_config.channel_configuration =
aac_config_32.channel_configuration;
aac_config.sample_rate = aac_config_32.sample_rate;
cmd = AUDIO_SET_AAC_CONFIG;
rc = audio_ioctl_shared(file, cmd, &aac_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
case AUDIO_SET_AAC_MIX_CONFIG: {
u32 mix_config;
pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG\n", __func__);
if (copy_from_user(&mix_config, (void *)arg,
sizeof(u32))) {
pr_err("%s: copy_from_user for AUDIO_SET_AAC_MIX_CONFIG failed\n"
, __func__);
rc = -EFAULT;
break;
}
rc = audio_ioctl_shared(file, cmd, &mix_config);
if (rc)
pr_err("%s:AUDIO_SET_AAC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default: {
pr_debug("Calling utils ioctl\n");
rc = audio->codec_compat_ioctl(file, cmd, arg);
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
struct msm_audio_aac_config *aac_config = NULL;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_multi_aac_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
aac_config = audio->codec_cfg;
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
audio->miscdevice = &audio_multiaac_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_multiaac_ws_mgr;
aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_MPEG4_MULTI_AAC);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open AAC decoder, expected frames is always 1
* audio->buf_cfg.frames_per_buf = 0x01;
*/
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_multi_aac_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_aac_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
__func__, audio->feedback, audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_aac_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_multiaac_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_multi_aac",
.fops = &audio_aac_fops,
};
static int __init audio_aac_init(void)
{
int ret = misc_register(&audio_multiaac_misc);
if (ret == 0)
device_init_wakeup(audio_multiaac_misc.this_device, true);
audio_multiaac_ws_mgr.ref_cnt = 0;
mutex_init(&audio_multiaac_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_aac_init);

191
dsp/codecs/audio_qcelp.c Arquivo normal
Ver arquivo

@@ -0,0 +1,191 @@
/* qcelp(v13k) audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "audio_utils_aio.h"
#define FRAME_SIZE_DEC_QCELP ((32) + sizeof(struct dec_meta_in))
static struct miscdevice audio_qcelp_misc;
static struct ws_mgr audio_qcelp_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_qcelp_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
audio->ac->session,
audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
}
return rc;
}
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_qcelp_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE_DEC_QCELP;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
audio->pcm_cfg.sample_rate = 8000;
audio->pcm_cfg.channel_count = 1;
audio->miscdevice = &audio_qcelp_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_qcelp_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_V13K);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_V13K);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_qcelp_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_qcelp_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio);
return rc;
}
static const struct file_operations audio_qcelp_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
};
static struct miscdevice audio_qcelp_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_qcelp",
.fops = &audio_qcelp_fops,
};
static int __init audio_qcelp_init(void)
{
int ret = misc_register(&audio_qcelp_misc);
if (ret == 0)
device_init_wakeup(audio_qcelp_misc.this_device, true);
audio_qcelp_ws_mgr.ref_cnt = 0;
mutex_init(&audio_qcelp_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_qcelp_init);

954
dsp/codecs/audio_utils.c Arquivo normal
Ver arquivo

@@ -0,0 +1,954 @@
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/compat.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/*
* Define maximum buffer size. Below values are chosen considering the higher
* values used among all native drivers.
*/
#define MAX_FRAME_SIZE 1536
#define MAX_FRAMES 5
#define META_SIZE (sizeof(struct meta_out_dsp))
#define MAX_BUFFER_SIZE (1 + ((MAX_FRAME_SIZE + META_SIZE) * MAX_FRAMES))
static int audio_in_pause(struct q6audio_in *audio)
{
int rc;
rc = q6asm_cmd(audio->ac, CMD_PAUSE);
if (rc < 0)
pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
audio->ac->session, rc);
return rc;
}
static int audio_in_flush(struct q6audio_in *audio)
{
int rc;
pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
/* Flush if session running */
if (audio->enabled) {
/* Implicitly issue a pause to the encoder before flushing */
rc = audio_in_pause(audio);
if (rc < 0) {
pr_err("%s:session id %d: pause cmd failed rc=%d\n",
__func__, audio->ac->session, rc);
return rc;
}
rc = q6asm_cmd(audio->ac, CMD_FLUSH);
if (rc < 0) {
pr_err("%s:session id %d: flush cmd failed rc=%d\n",
__func__, audio->ac->session, rc);
return rc;
}
/* 2nd arg: 0 -> run immediately
* 3rd arg: 0 -> msw_ts,
* 4th arg: 0 ->lsw_ts
*/
q6asm_run(audio->ac, 0x00, 0x00, 0x00);
pr_debug("Rerun the session\n");
}
audio->rflush = 1;
audio->wflush = 1;
memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
wake_up(&audio->read_wait);
/* get read_lock to ensure no more waiting read thread */
mutex_lock(&audio->read_lock);
audio->rflush = 0;
mutex_unlock(&audio->read_lock);
wake_up(&audio->write_wait);
/* get write_lock to ensure no more waiting write thread */
mutex_lock(&audio->write_lock);
audio->wflush = 0;
mutex_unlock(&audio->write_lock);
pr_debug("%s:session id %d: in_bytes %d\n", __func__,
audio->ac->session, atomic_read(&audio->in_bytes));
pr_debug("%s:session id %d: in_samples %d\n", __func__,
audio->ac->session, atomic_read(&audio->in_samples));
atomic_set(&audio->in_bytes, 0);
atomic_set(&audio->in_samples, 0);
atomic_set(&audio->out_count, 0);
return 0;
}
/* must be called with audio->lock held */
int audio_in_enable(struct q6audio_in *audio)
{
if (audio->enabled)
return 0;
/* 2nd arg: 0 -> run immediately
* 3rd arg: 0 -> msw_ts,
* 4th arg: 0 ->lsw_ts
*/
return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
}
/* must be called with audio->lock held */
int audio_in_disable(struct q6audio_in *audio)
{
int rc = 0;
if (!audio->stopped) {
audio->enabled = 0;
audio->opened = 0;
pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
__func__, audio->ac->session,
atomic_read(&audio->in_bytes),
atomic_read(&audio->in_samples));
rc = q6asm_cmd(audio->ac, CMD_CLOSE);
if (rc < 0)
pr_err("%s:session id %d: Failed to close the session rc=%d\n",
__func__, audio->ac->session,
rc);
audio->stopped = 1;
memset(audio->out_frame_info, 0,
sizeof(audio->out_frame_info));
wake_up(&audio->read_wait);
wake_up(&audio->write_wait);
}
pr_debug("%s:session id %d: enabled[%d]\n", __func__,
audio->ac->session, audio->enabled);
return rc;
}
int audio_in_buf_alloc(struct q6audio_in *audio)
{
int rc = 0;
switch (audio->buf_alloc) {
case NO_BUF_ALLOC:
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_audio_client_buf_alloc(IN,
audio->ac,
ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
audio->pcm_cfg.buffer_count);
if (rc < 0) {
pr_err("%s:session id %d: Buffer Alloc failed\n",
__func__,
audio->ac->session);
rc = -ENOMEM;
break;
}
audio->buf_alloc |= BUF_ALLOC_IN;
}
rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
audio->str_cfg.buffer_count);
if (rc < 0) {
pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENOMEM;
break;
}
audio->buf_alloc |= BUF_ALLOC_OUT;
break;
case BUF_ALLOC_IN:
rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
audio->str_cfg.buffer_count);
if (rc < 0) {
pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENOMEM;
break;
}
audio->buf_alloc |= BUF_ALLOC_OUT;
break;
case BUF_ALLOC_OUT:
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
audio->pcm_cfg.buffer_count);
if (rc < 0) {
pr_err("%s:session id %d: Buffer Alloc failed\n",
__func__,
audio->ac->session);
rc = -ENOMEM;
break;
}
audio->buf_alloc |= BUF_ALLOC_IN;
}
break;
default:
pr_debug("%s:session id %d: buf[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
}
return rc;
}
int audio_in_set_config(struct file *file,
struct msm_audio_config *cfg)
{
int rc = 0;
struct q6audio_in *audio = file->private_data;
if (audio->feedback != NON_TUNNEL_MODE) {
pr_err("%s:session id %d: Not sufficient permission to change the record mode\n",
__func__, audio->ac->session);
rc = -EACCES;
goto ret;
}
if ((cfg->buffer_count > PCM_BUF_COUNT) ||
(cfg->buffer_count == 1))
cfg->buffer_count = PCM_BUF_COUNT;
audio->pcm_cfg.buffer_count = cfg->buffer_count;
audio->pcm_cfg.buffer_size = cfg->buffer_size;
audio->pcm_cfg.channel_count = cfg->channel_count;
audio->pcm_cfg.sample_rate = cfg->sample_rate;
if (audio->opened && audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
audio->pcm_cfg.buffer_count);
if (rc < 0) {
pr_err("%s:session id %d: Buffer Alloc failed\n",
__func__, audio->ac->session);
rc = -ENOMEM;
goto ret;
}
}
audio->buf_alloc |= BUF_ALLOC_IN;
rc = 0;
pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
audio->ac->session, audio->pcm_cfg.buffer_count,
audio->pcm_cfg.buffer_size);
ret:
return rc;
}
/* ------------------- device --------------------- */
static long audio_in_ioctl_shared(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_FLUSH: {
/* Make sure we're stopped and we wake any threads
* that might be blocked holding the read_lock.
* While audio->stopped read threads will always
* exit immediately.
*/
rc = audio_in_flush(audio);
if (rc < 0)
pr_err("%s:session id %d: Flush Fail rc=%d\n",
__func__, audio->ac->session, rc);
else { /* Register back the flushed read buffer with DSP */
int cnt = 0;
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
pr_debug("register the read buffer\n");
}
break;
}
case AUDIO_PAUSE: {
pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
audio->ac->session);
if (audio->enabled)
audio_in_pause(audio);
break;
}
case AUDIO_GET_SESSION_ID: {
if (copy_to_user((void *) arg, &audio->ac->session,
sizeof(u16))) {
pr_err("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
__func__);
rc = -EFAULT;
}
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
long audio_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
return -EFAULT;
return rc;
}
mutex_lock(&audio->lock);
switch (cmd) {
case AUDIO_FLUSH:
case AUDIO_PAUSE:
case AUDIO_GET_SESSION_ID:
rc = audio_in_ioctl_shared(file, cmd, arg);
break;
case AUDIO_GET_STREAM_CONFIG: {
struct msm_audio_stream_config cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.buffer_size = audio->str_cfg.buffer_size;
cfg.buffer_count = audio->str_cfg.buffer_count;
if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
rc = -EFAULT;
pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
__func__, audio->ac->session, cfg.buffer_size,
cfg.buffer_count);
break;
}
case AUDIO_SET_STREAM_CONFIG: {
struct msm_audio_stream_config cfg;
if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG failed\n"
, __func__);
rc = -EFAULT;
break;
}
/* Minimum single frame size,
* but with in maximum frames number
*/
if ((cfg.buffer_size < (audio->min_frame_size +
sizeof(struct meta_out_dsp))) ||
(cfg.buffer_count < FRAME_NUM)) {
rc = -EINVAL;
break;
}
if (cfg.buffer_size > MAX_BUFFER_SIZE) {
rc = -EINVAL;
break;
}
audio->str_cfg.buffer_size = cfg.buffer_size;
audio->str_cfg.buffer_count = cfg.buffer_count;
if (audio->opened) {
rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
audio->str_cfg.buffer_count);
if (rc < 0) {
pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENOMEM;
break;
}
}
audio->buf_alloc |= BUF_ALLOC_OUT;
rc = 0;
pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
__func__, audio->ac->session,
audio->str_cfg.buffer_size,
audio->str_cfg.buffer_count);
break;
}
case AUDIO_SET_BUF_CFG: {
struct msm_audio_buf_cfg cfg;
if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
rc = -EFAULT;
break;
}
if ((audio->feedback == NON_TUNNEL_MODE) &&
!cfg.meta_info_enable) {
rc = -EFAULT;
break;
}
/* Restrict the num of frames per buf to coincide with
* default buf size
*/
if (cfg.frames_per_buf > audio->max_frames_per_buf) {
rc = -EFAULT;
break;
}
audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
__func__,
audio->ac->session, cfg.meta_info_enable,
cfg.frames_per_buf);
break;
}
case AUDIO_GET_BUF_CFG: {
pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
__func__,
audio->ac->session, audio->buf_cfg.meta_info_enable,
audio->buf_cfg.frames_per_buf);
if (copy_to_user((void *)arg, &audio->buf_cfg,
sizeof(struct msm_audio_buf_cfg)))
rc = -EFAULT;
break;
}
case AUDIO_GET_CONFIG: {
if (copy_to_user((void *)arg, &audio->pcm_cfg,
sizeof(struct msm_audio_config)))
rc = -EFAULT;
break;
}
case AUDIO_SET_CONFIG: {
struct msm_audio_config cfg;
if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
pr_err("%s: copy_from_user for AUDIO_SET_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = audio_in_set_config(file, &cfg);
break;
}
default:
/* call codec specific ioctl */
rc = audio->enc_ioctl(file, cmd, arg);
}
mutex_unlock(&audio->lock);
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_stats32 {
u32 byte_count;
u32 sample_count;
u32 unused[2];
};
struct msm_audio_stream_config32 {
u32 buffer_size;
u32 buffer_count;
};
struct msm_audio_config32 {
u32 buffer_size;
u32 buffer_count;
u32 channel_count;
u32 sample_rate;
u32 type;
u32 meta_field;
u32 bits;
u32 unused[3];
};
struct msm_audio_buf_cfg32 {
u32 meta_info_enable;
u32 frames_per_buf;
};
enum {
AUDIO_GET_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 3,
struct msm_audio_config32),
AUDIO_SET_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 4,
struct msm_audio_config32),
AUDIO_GET_STATS_32 = _IOR(AUDIO_IOCTL_MAGIC, 5,
struct msm_audio_stats32),
AUDIO_SET_STREAM_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 80,
struct msm_audio_stream_config32),
AUDIO_GET_STREAM_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 81,
struct msm_audio_stream_config32),
AUDIO_SET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 94,
struct msm_audio_buf_cfg32),
AUDIO_GET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 93,
struct msm_audio_buf_cfg32),
};
long audio_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
if (cmd == AUDIO_GET_STATS_32) {
struct msm_audio_stats32 stats_32;
memset(&stats_32, 0, sizeof(stats_32));
stats_32.byte_count = atomic_read(&audio->in_bytes);
stats_32.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats_32, sizeof(stats_32))) {
pr_err("%s: copy_to_user failed for AUDIO_GET_STATS_32\n",
__func__);
return -EFAULT;
}
return rc;
}
mutex_lock(&audio->lock);
switch (cmd) {
case AUDIO_FLUSH:
case AUDIO_PAUSE:
case AUDIO_GET_SESSION_ID:
rc = audio_in_ioctl_shared(file, cmd, arg);
break;
case AUDIO_GET_STREAM_CONFIG_32: {
struct msm_audio_stream_config32 cfg_32;
memset(&cfg_32, 0, sizeof(cfg_32));
cfg_32.buffer_size = audio->str_cfg.buffer_size;
cfg_32.buffer_count = audio->str_cfg.buffer_count;
if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
pr_err("%s: Copy to user failed\n", __func__);
rc = -EFAULT;
}
pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
__func__, audio->ac->session,
cfg_32.buffer_size,
cfg_32.buffer_count);
break;
}
case AUDIO_SET_STREAM_CONFIG_32: {
struct msm_audio_stream_config32 cfg_32;
struct msm_audio_stream_config cfg;
if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.buffer_size = cfg_32.buffer_size;
cfg.buffer_count = cfg_32.buffer_count;
/* Minimum single frame size,
* but with in maximum frames number
*/
if ((cfg.buffer_size < (audio->min_frame_size +
sizeof(struct meta_out_dsp))) ||
(cfg.buffer_count < FRAME_NUM)) {
rc = -EINVAL;
break;
}
audio->str_cfg.buffer_size = cfg.buffer_size;
audio->str_cfg.buffer_count = cfg.buffer_count;
if (audio->opened) {
rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
audio->str_cfg.buffer_count);
if (rc < 0) {
pr_err("%s: session id %d:\n",
__func__, audio->ac->session);
pr_err("Buffer Alloc failed rc=%d\n", rc);
rc = -ENOMEM;
break;
}
}
audio->buf_alloc |= BUF_ALLOC_OUT;
pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
__func__, audio->ac->session,
audio->str_cfg.buffer_size,
audio->str_cfg.buffer_count);
break;
}
case AUDIO_SET_BUF_CFG_32: {
struct msm_audio_buf_cfg32 cfg_32;
struct msm_audio_buf_cfg cfg;
if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_BUG_CFG_32 failed",
__func__);
rc = -EFAULT;
break;
}
cfg.meta_info_enable = cfg_32.meta_info_enable;
cfg.frames_per_buf = cfg_32.frames_per_buf;
if ((audio->feedback == NON_TUNNEL_MODE) &&
!cfg.meta_info_enable) {
rc = -EFAULT;
break;
}
/* Restrict the num of frames per buf to coincide with
* default buf size
*/
if (cfg.frames_per_buf > audio->max_frames_per_buf) {
rc = -EFAULT;
break;
}
audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
__func__, audio->ac->session, cfg.meta_info_enable,
cfg.frames_per_buf);
break;
}
case AUDIO_GET_BUF_CFG_32: {
struct msm_audio_buf_cfg32 cfg_32;
pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
__func__,
audio->ac->session, audio->buf_cfg.meta_info_enable,
audio->buf_cfg.frames_per_buf);
cfg_32.meta_info_enable = audio->buf_cfg.meta_info_enable;
cfg_32.frames_per_buf = audio->buf_cfg.frames_per_buf;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(struct msm_audio_buf_cfg32))) {
pr_err("%s: Copy to user failed\n", __func__);
rc = -EFAULT;
}
break;
}
case AUDIO_GET_CONFIG_32: {
struct msm_audio_config32 cfg_32;
memset(&cfg_32, 0, sizeof(cfg_32));
cfg_32.buffer_size = audio->pcm_cfg.buffer_size;
cfg_32.buffer_count = audio->pcm_cfg.buffer_count;
cfg_32.channel_count = audio->pcm_cfg.channel_count;
cfg_32.sample_rate = audio->pcm_cfg.sample_rate;
cfg_32.type = audio->pcm_cfg.type;
cfg_32.meta_field = audio->pcm_cfg.meta_field;
cfg_32.bits = audio->pcm_cfg.bits;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(struct msm_audio_config32))) {
pr_err("%s: Copy to user failed\n", __func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_CONFIG_32: {
struct msm_audio_config32 cfg_32;
struct msm_audio_config cfg;
if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.buffer_size = cfg_32.buffer_size;
cfg.buffer_count = cfg_32.buffer_count;
cfg.channel_count = cfg_32.channel_count;
cfg.sample_rate = cfg_32.sample_rate;
cfg.type = cfg_32.type;
cfg.meta_field = cfg_32.meta_field;
cfg.bits = cfg_32.bits;
rc = audio_in_set_config(file, &cfg);
break;
}
default:
/* call codec specific ioctl */
rc = audio->enc_compat_ioctl(file, cmd, arg);
}
mutex_unlock(&audio->lock);
return rc;
}
#endif
ssize_t audio_in_read(struct file *file,
char __user *buf,
size_t count, loff_t *pos)
{
struct q6audio_in *audio = file->private_data;
const char __user *start = buf;
unsigned char *data;
uint32_t offset = 0;
uint32_t size = 0;
int rc = 0;
uint32_t idx;
struct meta_out_dsp meta;
uint32_t bytes_to_copy = 0;
uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
(sizeof(unsigned char) +
(sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
memset(&meta, 0, sizeof(meta));
pr_debug("%s:session id %d: read - %zd\n", __func__, audio->ac->session,
count);
if (audio->reset_event)
return -ENETRESET;
if (!audio->enabled)
return -EFAULT;
mutex_lock(&audio->read_lock);
while (count > 0) {
rc = wait_event_interruptible(
audio->read_wait,
((atomic_read(&audio->out_count) > 0) ||
(audio->stopped) ||
audio->rflush || audio->eos_rsp ||
audio->event_abort));
if (audio->event_abort) {
rc = -EIO;
break;
}
if (rc < 0)
break;
if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
audio->rflush) {
pr_debug("%s:session id %d: driver in stop state or flush,No more buf to read",
__func__,
audio->ac->session);
rc = 0;/* End of File */
break;
}
if (!(atomic_read(&audio->out_count)) &&
(audio->eos_rsp == 1) &&
(count >= (sizeof(unsigned char) +
sizeof(struct meta_out_dsp)))) {
unsigned char num_of_frames;
pr_info("%s:session id %d: eos %d at output\n",
__func__, audio->ac->session, audio->eos_rsp);
if (buf != start)
break;
num_of_frames = 0xFF;
if (copy_to_user(buf, &num_of_frames,
sizeof(unsigned char))) {
rc = -EFAULT;
break;
}
buf += sizeof(unsigned char);
meta.frame_size = 0xFFFF;
meta.encoded_pcm_samples = 0xFFFF;
meta.msw_ts = 0x00;
meta.lsw_ts = 0x00;
meta.nflags = AUD_EOS_SET;
audio->eos_rsp = 0;
if (copy_to_user(buf, &meta, sizeof(meta))) {
rc = -EFAULT;
break;
}
buf += sizeof(meta);
break;
}
data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
&size, &idx);
if ((count >= (size + mfield_size)) && data) {
if (audio->buf_cfg.meta_info_enable) {
if (copy_to_user(buf,
&audio->out_frame_info[idx][0],
sizeof(unsigned char))) {
rc = -EFAULT;
break;
}
bytes_to_copy =
(size + audio->out_frame_info[idx][1]);
/* Number of frames information copied */
buf += sizeof(unsigned char);
count -= sizeof(unsigned char);
} else {
offset = audio->out_frame_info[idx][1];
bytes_to_copy = size;
}
pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
__func__, audio->ac->session,
audio->out_frame_info[idx][1],
audio->out_frame_info[idx][0]);
if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
rc = -EFAULT;
break;
}
count -= bytes_to_copy;
buf += bytes_to_copy;
} else {
pr_err("%s:session id %d: short read data[%pK] bytesavail[%d]bytesrequest[%zd]\n",
__func__,
audio->ac->session,
data, size, count);
}
atomic_dec(&audio->out_count);
q6asm_read(audio->ac);
break;
}
mutex_unlock(&audio->read_lock);
pr_debug("%s:session id %d: read: %zd bytes\n", __func__,
audio->ac->session, (buf-start));
if (buf > start)
return buf - start;
return rc;
}
static int extract_meta_info(char *buf, unsigned long *msw_ts,
unsigned long *lsw_ts, unsigned int *flags)
{
struct meta_in *meta = (struct meta_in *)buf;
*msw_ts = meta->ntimestamp.highpart;
*lsw_ts = meta->ntimestamp.lowpart;
*flags = meta->nflags;
return 0;
}
ssize_t audio_in_write(struct file *file,
const char __user *buf,
size_t count, loff_t *pos)
{
struct q6audio_in *audio = file->private_data;
const char __user *start = buf;
size_t xfer = 0;
char *cpy_ptr;
int rc = 0;
unsigned char *data;
uint32_t size = 0;
uint32_t idx = 0;
uint32_t nflags = 0;
unsigned long msw_ts = 0;
unsigned long lsw_ts = 0;
uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
sizeof(struct meta_in);
pr_debug("%s:session id %d: to write[%zd]\n", __func__,
audio->ac->session, count);
if (audio->reset_event)
return -ENETRESET;
if (!audio->enabled)
return -EFAULT;
mutex_lock(&audio->write_lock);
while (count > 0) {
rc = wait_event_interruptible(audio->write_wait,
((atomic_read(&audio->in_count) > 0) ||
(audio->stopped) ||
(audio->wflush) || (audio->event_abort)));
if (audio->event_abort) {
rc = -EIO;
break;
}
if (rc < 0)
break;
if (audio->stopped || audio->wflush) {
pr_debug("%s: session id %d: stop or flush\n", __func__,
audio->ac->session);
rc = -EBUSY;
break;
}
/* if no PCM data, might have only eos buffer
* such case do not hold cpu buffer
*/
if ((buf == start) && (count == mfield_size)) {
char eos_buf[sizeof(struct meta_in)];
/* Processing beginning of user buffer */
if (copy_from_user(eos_buf, buf, mfield_size)) {
rc = -EFAULT;
break;
}
/* Check if EOS flag is set and buffer has
* contains just meta field
*/
extract_meta_info(eos_buf, &msw_ts, &lsw_ts,
&nflags);
buf += mfield_size;
/* send the EOS and return */
pr_debug("%s:session id %d: send EOS 0x%8x\n",
__func__,
audio->ac->session, nflags);
break;
}
data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
&size, &idx);
if (!data) {
pr_debug("%s:session id %d: No buf available\n",
__func__, audio->ac->session);
continue;
}
cpy_ptr = data;
if (audio->buf_cfg.meta_info_enable) {
if (buf == start) {
/* Processing beginning of user buffer */
if (copy_from_user(cpy_ptr, buf, mfield_size)) {
rc = -EFAULT;
break;
}
/* Check if EOS flag is set and buffer has
* contains just meta field
*/
extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
&nflags);
buf += mfield_size;
count -= mfield_size;
} else {
pr_debug("%s:session id %d: continuous buffer\n",
__func__, audio->ac->session);
}
}
xfer = (count > (audio->pcm_cfg.buffer_size)) ?
(audio->pcm_cfg.buffer_size) : count;
if (copy_from_user(cpy_ptr, buf, xfer)) {
rc = -EFAULT;
break;
}
rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
if (rc < 0) {
rc = -EFAULT;
break;
}
atomic_dec(&audio->in_count);
count -= xfer;
buf += xfer;
}
mutex_unlock(&audio->write_lock);
pr_debug("%s:session id %d: eos_condition 0x%x buf[0x%pK] start[0x%pK]\n",
__func__, audio->ac->session,
nflags, buf, start);
if (nflags & AUD_EOS_SET) {
rc = q6asm_cmd(audio->ac, CMD_EOS);
pr_info("%s:session id %d: eos %d at input\n", __func__,
audio->ac->session, audio->eos_rsp);
}
pr_debug("%s:session id %d: Written %zd Avail Buf[%d]", __func__,
audio->ac->session, (buf - start - mfield_size),
atomic_read(&audio->in_count));
if (!rc) {
if (buf > start)
return buf - start;
}
return rc;
}
int audio_in_release(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = file->private_data;
pr_info("%s: session id %d\n", __func__, audio->ac->session);
mutex_lock(&audio->lock);
audio_in_disable(audio);
q6asm_audio_client_free(audio->ac);
mutex_unlock(&audio->lock);
kfree(audio->enc_cfg);
kfree(audio->codec_cfg);
kfree(audio);
return 0;
}

114
dsp/codecs/audio_utils.h Arquivo normal
Ver arquivo

@@ -0,0 +1,114 @@
/* Copyright (c) 2010-2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/msm_audio.h>
#include <linux/compat.h>
#include "q6audio_common.h"
#define FRAME_NUM (8)
#define PCM_BUF_COUNT (2)
#define AUD_EOS_SET 0x01
#define TUNNEL_MODE 0x0000
#define NON_TUNNEL_MODE 0x0001
#define NO_BUF_ALLOC 0x00
#define BUF_ALLOC_IN 0x01
#define BUF_ALLOC_OUT 0x02
#define BUF_ALLOC_INOUT 0x03
#define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
struct timestamp {
u32 lowpart;
u32 highpart;
} __packed;
struct meta_in {
unsigned short offset;
struct timestamp ntimestamp;
unsigned int nflags;
} __packed;
struct meta_out_dsp {
u32 offset_to_frame;
u32 frame_size;
u32 encoded_pcm_samples;
u32 msw_ts;
u32 lsw_ts;
u32 nflags;
} __packed;
struct meta_out {
unsigned char num_of_frames;
struct meta_out_dsp meta_out_dsp[];
} __packed;
struct q6audio_in {
spinlock_t dsp_lock;
atomic_t in_bytes;
atomic_t in_samples;
struct mutex lock;
struct mutex read_lock;
struct mutex write_lock;
wait_queue_head_t read_wait;
wait_queue_head_t write_wait;
struct audio_client *ac;
struct msm_audio_stream_config str_cfg;
void *enc_cfg;
struct msm_audio_buf_cfg buf_cfg;
struct msm_audio_config pcm_cfg;
void *codec_cfg;
/* number of buffers available to read/write */
atomic_t in_count;
atomic_t out_count;
/* first idx: num of frames per buf, second idx: offset to frame */
uint32_t out_frame_info[FRAME_NUM][2];
int eos_rsp;
int opened;
int enabled;
int stopped;
int event_abort;
int feedback; /* Flag indicates whether used
* in Non Tunnel mode
*/
int rflush;
int wflush;
int buf_alloc;
uint16_t min_frame_size;
uint16_t max_frames_per_buf;
bool reset_event;
long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
long (*enc_compat_ioctl)(struct file *, unsigned int, unsigned long);
};
int audio_in_enable(struct q6audio_in *audio);
int audio_in_disable(struct q6audio_in *audio);
int audio_in_buf_alloc(struct q6audio_in *audio);
long audio_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
long audio_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
#else
#define audio_in_compat_ioctl NULL
#endif
ssize_t audio_in_read(struct file *file, char __user *buf,
size_t count, loff_t *pos);
ssize_t audio_in_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos);
int audio_in_release(struct inode *inode, struct file *file);
int audio_in_set_config(struct file *file, struct msm_audio_config *cfg);

2142
dsp/codecs/audio_utils_aio.c Arquivo normal

Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff

232
dsp/codecs/audio_utils_aio.h Arquivo normal
Ver arquivo

@@ -0,0 +1,232 @@
/* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/msm_audio.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/msm_ion.h>
#include <asm/ioctls.h>
#include <linux/atomic.h>
#include "q6audio_common.h"
#define TUNNEL_MODE 0x0000
#define NON_TUNNEL_MODE 0x0001
#define ADRV_STATUS_AIO_INTF 0x00000001 /* AIO interface */
#define ADRV_STATUS_FSYNC 0x00000008
#define ADRV_STATUS_PAUSE 0x00000010
#define AUDIO_DEC_EOS_SET 0x00000001
#define AUDIO_DEC_EOF_SET 0x00000010
#define AUDIO_EVENT_NUM 10
#define __CONTAINS(r, v, l) ({ \
typeof(r) __r = r; \
typeof(v) __v = v; \
typeof(v) __e = __v + l; \
int res = ((__v >= __r->vaddr) && \
(__e <= __r->vaddr + __r->len)); \
res; \
})
#define CONTAINS(r1, r2) ({ \
typeof(r2) __r2 = r2; \
__CONTAINS(r1, __r2->vaddr, __r2->len); \
})
#define IN_RANGE(r, v) ({ \
typeof(r) __r = r; \
typeof(v) __vv = v; \
int res = ((__vv >= __r->vaddr) && \
(__vv < (__r->vaddr + __r->len))); \
res; \
})
#define OVERLAPS(r1, r2) ({ \
typeof(r1) __r1 = r1; \
typeof(r2) __r2 = r2; \
typeof(__r2->vaddr) __v = __r2->vaddr; \
typeof(__v) __e = __v + __r2->len - 1; \
int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
res; \
})
struct timestamp {
u32 lowpart;
u32 highpart;
} __packed;
struct meta_out_dsp {
u32 offset_to_frame;
u32 frame_size;
u32 encoded_pcm_samples;
u32 msw_ts;
u32 lsw_ts;
u32 nflags;
} __packed;
struct dec_meta_in {
unsigned char reserved[18];
unsigned short offset;
struct timestamp ntimestamp;
unsigned int nflags;
} __packed;
struct dec_meta_out {
unsigned int reserved[7];
unsigned int num_of_frames;
struct meta_out_dsp meta_out_dsp[];
} __packed;
/* General meta field to store meta info locally */
union meta_data {
struct dec_meta_out meta_out;
struct dec_meta_in meta_in;
} __packed;
/* per device wakeup source manager */
struct ws_mgr {
struct mutex ws_lock;
uint32_t ref_cnt;
};
#define PCM_BUF_COUNT (2)
/* Buffer with meta */
#define PCM_BUFSZ_MIN ((4*1024) + sizeof(struct dec_meta_out))
/* FRAME_NUM must be a power of two */
#define FRAME_NUM (2)
#define FRAME_SIZE ((4*1536) + sizeof(struct dec_meta_in))
struct audio_aio_ion_region {
struct list_head list;
struct ion_handle *handle;
int fd;
void *vaddr;
phys_addr_t paddr;
void *kvaddr;
unsigned long len;
unsigned int ref_cnt;
};
struct audio_aio_event {
struct list_head list;
int event_type;
union msm_audio_event_payload payload;
};
struct audio_aio_buffer_node {
struct list_head list;
struct msm_audio_aio_buf buf;
unsigned long paddr;
uint32_t token;
void *kvaddr;
union meta_data meta_info;
};
struct q6audio_aio;
struct audio_aio_drv_operations {
void (*out_flush)(struct q6audio_aio *);
void (*in_flush)(struct q6audio_aio *);
};
struct q6audio_aio {
atomic_t in_bytes;
atomic_t in_samples;
struct msm_audio_stream_config str_cfg;
struct msm_audio_buf_cfg buf_cfg;
struct msm_audio_config pcm_cfg;
void *codec_cfg;
struct audio_client *ac;
struct mutex lock;
struct mutex read_lock;
struct mutex write_lock;
struct mutex get_event_lock;
wait_queue_head_t cmd_wait;
wait_queue_head_t write_wait;
wait_queue_head_t event_wait;
spinlock_t dsp_lock;
spinlock_t event_queue_lock;
struct miscdevice *miscdevice;
uint32_t wakelock_voted;
struct ws_mgr *audio_ws_mgr;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
#endif
struct list_head out_queue; /* queue to retain output buffers */
struct list_head in_queue; /* queue to retain input buffers */
struct list_head free_event_queue;
struct list_head event_queue;
struct list_head ion_region_queue; /* protected by lock */
struct ion_client *client;
struct audio_aio_drv_operations drv_ops;
union msm_audio_event_payload eos_write_payload;
uint32_t device_events;
uint16_t volume;
uint32_t drv_status;
int event_abort;
int eos_rsp;
int eos_flag;
int opened;
int enabled;
int stopped;
int feedback;
int rflush; /* Read flush */
int wflush; /* Write flush */
bool reset_event;
long (*codec_ioctl)(struct file *, unsigned int, unsigned long);
long (*codec_compat_ioctl)(struct file *, unsigned int, unsigned long);
};
void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload);
void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload);
int insert_eos_buf(struct q6audio_aio *audio,
struct audio_aio_buffer_node *buf_node);
void extract_meta_out_info(struct q6audio_aio *audio,
struct audio_aio_buffer_node *buf_node, int dir);
int audio_aio_open(struct q6audio_aio *audio, struct file *file);
int audio_aio_enable(struct q6audio_aio *audio);
void audio_aio_post_event(struct q6audio_aio *audio, int type,
union msm_audio_event_payload payload);
int audio_aio_release(struct inode *inode, struct file *file);
int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
void audio_aio_async_out_flush(struct q6audio_aio *audio);
void audio_aio_async_in_flush(struct q6audio_aio *audio);
void audio_aio_ioport_reset(struct q6audio_aio *audio);
int enable_volume_ramp(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
int audio_aio_debug_open(struct inode *inode, struct file *file);
ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
#endif

345
dsp/codecs/audio_wma.c Arquivo normal
Ver arquivo

@@ -0,0 +1,345 @@
/* wma audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_wma.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_wma_misc;
static struct ws_mgr audio_wma_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_wma_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_wma_cfg wma_cfg;
struct msm_audio_wma_config_v2 *wma_config;
pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
audio, audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
wma_cfg.format_tag = wma_config->format_tag;
wma_cfg.ch_cfg = wma_config->numchannels;
wma_cfg.sample_rate = wma_config->samplingrate;
wma_cfg.avg_bytes_per_sec = wma_config->avgbytespersecond;
wma_cfg.block_align = wma_config->block_align;
wma_cfg.valid_bits_per_sample =
wma_config->validbitspersample;
wma_cfg.ch_mask = wma_config->channelmask;
wma_cfg.encode_opt = wma_config->encodeopt;
/* Configure Media format block */
rc = q6asm_media_format_block_wma(audio->ac, &wma_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_WMA_CONFIG_V2: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_wma_config_v2))) {
pr_err("%s:copy_to_user for AUDIO_SET_WMA_CONFIG_V2 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_WMA_CONFIG_V2: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_wma_config_v2))) {
pr_err("%s:copy_from_user for AUDIO_SET_WMA_CONFIG_V2 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_wma_config_v2_32 {
u16 format_tag;
u16 numchannels;
u32 samplingrate;
u32 avgbytespersecond;
u16 block_align;
u16 validbitspersample;
u32 channelmask;
u16 encodeopt;
};
enum {
AUDIO_GET_WMA_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_wma_config_v2_32),
AUDIO_SET_WMA_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_wma_config_v2_32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
case AUDIO_GET_WMA_CONFIG_V2_32: {
struct msm_audio_wma_config_v2 *wma_config;
struct msm_audio_wma_config_v2_32 wma_config_32;
memset(&wma_config_32, 0, sizeof(wma_config_32));
wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
wma_config_32.format_tag = wma_config->format_tag;
wma_config_32.numchannels = wma_config->numchannels;
wma_config_32.samplingrate = wma_config->samplingrate;
wma_config_32.avgbytespersecond = wma_config->avgbytespersecond;
wma_config_32.block_align = wma_config->block_align;
wma_config_32.validbitspersample =
wma_config->validbitspersample;
wma_config_32.channelmask = wma_config->channelmask;
wma_config_32.encodeopt = wma_config->encodeopt;
if (copy_to_user((void *)arg, &wma_config_32,
sizeof(wma_config_32))) {
pr_err("%s: copy_to_user for GET_WMA_CONFIG_V2_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_SET_WMA_CONFIG_V2_32: {
struct msm_audio_wma_config_v2 *wma_config;
struct msm_audio_wma_config_v2_32 wma_config_32;
if (copy_from_user(&wma_config_32, (void *)arg,
sizeof(wma_config_32))) {
pr_err("%s: copy_from_user for SET_WMA_CONFIG_V2_32 failed\n"
, __func__);
rc = -EFAULT;
break;
}
wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
wma_config->format_tag = wma_config_32.format_tag;
wma_config->numchannels = wma_config_32.numchannels;
wma_config->samplingrate = wma_config_32.samplingrate;
wma_config->avgbytespersecond = wma_config_32.avgbytespersecond;
wma_config->block_align = wma_config_32.block_align;
wma_config->validbitspersample =
wma_config_32.validbitspersample;
wma_config->channelmask = wma_config_32.channelmask;
wma_config->encodeopt = wma_config_32.encodeopt;
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_wma_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wma_config_v2),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_wma_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_wma_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_WMA_V9);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open WMA decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_WMA_V9);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_wma_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_wma_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:wmadec success mode[%d]session[%d]\n", __func__,
audio->feedback,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_wma_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_wma_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_wma",
.fops = &audio_wma_fops,
};
static int __init audio_wma_init(void)
{
int ret = misc_register(&audio_wma_misc);
if (ret == 0)
device_init_wakeup(audio_wma_misc.this_device, true);
audio_wma_ws_mgr.ref_cnt = 0;
mutex_init(&audio_wma_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_wma_init);

418
dsp/codecs/audio_wmapro.c Arquivo normal
Ver arquivo

@@ -0,0 +1,418 @@
/* wmapro audio output device
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/msm_audio_wmapro.h>
#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_wmapro_misc;
static struct ws_mgr audio_wmapro_ws_mgr;
#ifdef CONFIG_DEBUG_FS
static const struct file_operations audio_wmapro_debug_fops = {
.read = audio_aio_debug_read,
.open = audio_aio_debug_open,
};
#endif
static long audio_ioctl_shared(struct file *file, unsigned int cmd,
void *arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START: {
struct asm_wmapro_cfg wmapro_cfg;
struct msm_audio_wmapro_config *wmapro_config;
pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count,
16, /* bits per sample */
true, /* use default channel map */
true, /* use back channel map flavor */
NULL);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
}
}
wmapro_config = (struct msm_audio_wmapro_config *)
audio->codec_cfg;
if ((wmapro_config->formattag == 0x162) ||
(wmapro_config->formattag == 0x163) ||
(wmapro_config->formattag == 0x166) ||
(wmapro_config->formattag == 0x167)) {
wmapro_cfg.format_tag = wmapro_config->formattag;
} else {
pr_err("%s:AUDIO_START failed: formattag = %d\n",
__func__, wmapro_config->formattag);
rc = -EINVAL;
break;
}
if (wmapro_config->numchannels > 0) {
wmapro_cfg.ch_cfg = wmapro_config->numchannels;
} else {
pr_err("%s:AUDIO_START failed: channels = %d\n",
__func__, wmapro_config->numchannels);
rc = -EINVAL;
break;
}
if (wmapro_config->samplingrate > 0) {
wmapro_cfg.sample_rate = wmapro_config->samplingrate;
} else {
pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
__func__, wmapro_config->samplingrate);
rc = -EINVAL;
break;
}
wmapro_cfg.avg_bytes_per_sec =
wmapro_config->avgbytespersecond;
if ((wmapro_config->asfpacketlength <= 13376) ||
(wmapro_config->asfpacketlength > 0)) {
wmapro_cfg.block_align =
wmapro_config->asfpacketlength;
} else {
pr_err("%s:AUDIO_START failed: block_align = %d\n",
__func__, wmapro_config->asfpacketlength);
rc = -EINVAL;
break;
}
if ((wmapro_config->validbitspersample == 16) ||
(wmapro_config->validbitspersample == 24)) {
wmapro_cfg.valid_bits_per_sample =
wmapro_config->validbitspersample;
} else {
pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
__func__, wmapro_config->validbitspersample);
rc = -EINVAL;
break;
}
wmapro_cfg.ch_mask = wmapro_config->channelmask;
wmapro_cfg.encode_opt = wmapro_config->encodeopt;
wmapro_cfg.adv_encode_opt =
wmapro_config->advancedencodeopt;
wmapro_cfg.adv_encode_opt2 =
wmapro_config->advancedencodeopt2;
/* Configure Media format block */
rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg,
audio->ac->stream_id);
if (rc < 0) {
pr_err("cmd media format block failed\n");
break;
}
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("Audio Start procedure failed rc=%d\n", rc);
break;
}
pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
if (audio->stopped == 1)
audio->stopped = 0;
break;
}
default:
pr_err("%s: Unknown ioctl cmd %d\n", __func__, cmd);
rc = -EINVAL;
break;
}
return rc;
}
static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_GET_WMAPRO_CONFIG: {
if (copy_to_user((void *)arg, audio->codec_cfg,
sizeof(struct msm_audio_wmapro_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_WMAPRO_CONFIG: {
if (copy_from_user(audio->codec_cfg, (void *)arg,
sizeof(struct msm_audio_wmapro_config))) {
pr_err("%s: copy_from_user for AUDIO_SET_WMAPRO_CONFIG_V2 failed\n",
__func__);
rc = -EFAULT;
break;
}
break;
}
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_wmapro_config32 {
u16 armdatareqthr;
u8 validbitspersample;
u8 numchannels;
u16 formattag;
u32 samplingrate;
u32 avgbytespersecond;
u16 asfpacketlength;
u32 channelmask;
u16 encodeopt;
u16 advancedencodeopt;
u32 advancedencodeopt2;
};
enum {
AUDIO_GET_WMAPRO_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_wmapro_config32),
AUDIO_SET_WMAPRO_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_wmapro_config32)
};
static long audio_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct q6audio_aio *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_GET_WMAPRO_CONFIG_32: {
struct msm_audio_wmapro_config *wmapro_config;
struct msm_audio_wmapro_config32 wmapro_config_32;
memset(&wmapro_config_32, 0, sizeof(wmapro_config_32));
wmapro_config =
(struct msm_audio_wmapro_config *)audio->codec_cfg;
wmapro_config_32.armdatareqthr = wmapro_config->armdatareqthr;
wmapro_config_32.validbitspersample =
wmapro_config->validbitspersample;
wmapro_config_32.numchannels = wmapro_config->numchannels;
wmapro_config_32.formattag = wmapro_config->formattag;
wmapro_config_32.samplingrate = wmapro_config->samplingrate;
wmapro_config_32.avgbytespersecond =
wmapro_config->avgbytespersecond;
wmapro_config_32.asfpacketlength =
wmapro_config->asfpacketlength;
wmapro_config_32.channelmask = wmapro_config->channelmask;
wmapro_config_32.encodeopt = wmapro_config->encodeopt;
wmapro_config_32.advancedencodeopt =
wmapro_config->advancedencodeopt;
wmapro_config_32.advancedencodeopt2 =
wmapro_config->advancedencodeopt2;
if (copy_to_user((void *)arg, &wmapro_config_32,
sizeof(struct msm_audio_wmapro_config32))) {
pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG_V2_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_WMAPRO_CONFIG_32: {
struct msm_audio_wmapro_config *wmapro_config;
struct msm_audio_wmapro_config32 wmapro_config_32;
if (copy_from_user(&wmapro_config_32, (void *)arg,
sizeof(struct msm_audio_wmapro_config32))) {
pr_err(
"%s: copy_from_user for AUDIO_SET_WMAPRO_CONFG_V2_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
wmapro_config =
(struct msm_audio_wmapro_config *)audio->codec_cfg;
wmapro_config->armdatareqthr = wmapro_config_32.armdatareqthr;
wmapro_config->validbitspersample =
wmapro_config_32.validbitspersample;
wmapro_config->numchannels = wmapro_config_32.numchannels;
wmapro_config->formattag = wmapro_config_32.formattag;
wmapro_config->samplingrate = wmapro_config_32.samplingrate;
wmapro_config->avgbytespersecond =
wmapro_config_32.avgbytespersecond;
wmapro_config->asfpacketlength =
wmapro_config_32.asfpacketlength;
wmapro_config->channelmask = wmapro_config_32.channelmask;
wmapro_config->encodeopt = wmapro_config_32.encodeopt;
wmapro_config->advancedencodeopt =
wmapro_config_32.advancedencodeopt;
wmapro_config->advancedencodeopt2 =
wmapro_config_32.advancedencodeopt2;
break;
}
case AUDIO_START: {
rc = audio_ioctl_shared(file, cmd, (void *)arg);
break;
}
default: {
pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
rc = audio->codec_compat_ioctl(file, cmd, arg);
if (rc)
pr_err("Failed in utils_ioctl: %d\n", rc);
break;
}
}
return rc;
}
#else
#define audio_compat_ioctl NULL
#endif
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
int rc = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_wmapro_" + 5];
#endif
audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
audio->miscdevice = &audio_wmapro_misc;
audio->wakelock_voted = false;
audio->audio_ws_mgr = &audio_wmapro_ws_mgr;
audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
(void *)audio);
if (!audio->ac) {
pr_err("Could not allocate memory for audio client\n");
kfree(audio->codec_cfg);
kfree(audio);
return -ENOMEM;
}
rc = audio_aio_open(audio, file);
if (rc < 0) {
pr_err("%s: audio_aio_open rc=%d\n",
__func__, rc);
goto fail;
}
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
FORMAT_WMA_V10PRO);
if (rc < 0) {
pr_err("NT mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = NON_TUNNEL_MODE;
/* open WMA decoder, expected frames is always 1*/
audio->buf_cfg.frames_per_buf = 0x01;
audio->buf_cfg.meta_info_enable = 0x01;
} else if ((file->f_mode & FMODE_WRITE) &&
!(file->f_mode & FMODE_READ)) {
rc = q6asm_open_write(audio->ac, FORMAT_WMA_V10PRO);
if (rc < 0) {
pr_err("T mode Open failed rc=%d\n", rc);
rc = -ENODEV;
goto fail;
}
audio->feedback = TUNNEL_MODE;
audio->buf_cfg.meta_info_enable = 0x00;
} else {
pr_err("Not supported mode\n");
rc = -EACCES;
goto fail;
}
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "msm_wmapro_%04x", audio->ac->session);
audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
NULL, (void *)audio,
&audio_wmapro_debug_fops);
if (IS_ERR(audio->dentry))
pr_debug("debugfs_create_file failed\n");
#endif
pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
audio->ac->session);
return rc;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_wmapro_fops = {
.owner = THIS_MODULE,
.open = audio_open,
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
.compat_ioctl = audio_compat_ioctl
};
static struct miscdevice audio_wmapro_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_wmapro",
.fops = &audio_wmapro_fops,
};
static int __init audio_wmapro_init(void)
{
int ret = misc_register(&audio_wmapro_misc);
if (ret == 0)
device_init_wakeup(audio_wmapro_misc.this_device, true);
audio_wmapro_ws_mgr.ref_cnt = 0;
mutex_init(&audio_wmapro_ws_mgr.ws_lock);
return ret;
}
device_initcall(audio_wmapro_init);

410
dsp/codecs/evrc_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,410 @@
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_qcp.h>
#include <linux/atomic.h>
#include <linux/compat.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((23+sizeof(struct meta_out_dsp)) * 10))
static long evrc_in_ioctl_shared(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_evrc_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
pr_info("%s:AUDIO_START already over\n", __func__);
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed\n",
__func__, audio->ac->session);
break;
}
/* rate_modulation_cmd set to zero
* currently not configurable from user space
*/
rc = q6asm_enc_cfg_blk_evrc(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate, 0);
if (rc < 0) {
pr_err("%s:session id %d: cmd evrc media format block failed\n",
__func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed\n",
__func__, audio->ac->session);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
break;
}
case AUDIO_SET_EVRC_ENC_CONFIG: {
struct msm_audio_evrc_enc_config *cfg;
struct msm_audio_evrc_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
cfg = (struct msm_audio_evrc_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer for %s\n",
__func__, "AUDIO_SET_EVRC_ENC_CONFIG");
rc = -EINVAL;
break;
}
if (cfg->min_bit_rate > 4 ||
cfg->min_bit_rate < 1 ||
(cfg->min_bit_rate == 2)) {
pr_err("%s:session id %d: invalid min bitrate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
if (cfg->max_bit_rate > 4 ||
cfg->max_bit_rate < 1 ||
(cfg->max_bit_rate == 2)) {
pr_err("%s:session id %d: invalid max bitrate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
enc_cfg->min_bit_rate = cfg->min_bit_rate;
enc_cfg->max_bit_rate = cfg->max_bit_rate;
pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
__func__,
audio->ac->session, enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
static long evrc_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = evrc_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_EVRC_ENC_CONFIG: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_evrc_enc_config))) {
pr_err("%s: copy_to_user for AUDIO_GET_EVRC_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_EVRC_ENC_CONFIG: {
struct msm_audio_evrc_enc_config cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(struct msm_audio_evrc_enc_config))) {
pr_err("%s: copy_from_user for AUDIO_SET_EVRC_ENC_CONFIG failed\n",
__func__);
rc = -EFAULT;
break;
}
rc = evrc_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_EVRC_ENC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_evrc_enc_config32 {
u32 cdma_rate;
u32 min_bit_rate;
u32 max_bit_rate;
};
enum {
AUDIO_SET_EVRC_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
2, struct msm_audio_evrc_enc_config32),
AUDIO_GET_EVRC_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
3, struct msm_audio_evrc_enc_config32)
};
static long evrc_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = evrc_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_EVRC_ENC_CONFIG_32: {
struct msm_audio_evrc_enc_config32 cfg_32;
struct msm_audio_evrc_enc_config *enc_cfg;
memset(&cfg_32, 0, sizeof(cfg_32));
enc_cfg = audio->enc_cfg;
cfg_32.cdma_rate = enc_cfg->cdma_rate;
cfg_32.min_bit_rate = enc_cfg->min_bit_rate;
cfg_32.max_bit_rate = enc_cfg->max_bit_rate;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(cfg_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_EVRC_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_EVRC_ENC_CONFIG_32: {
struct msm_audio_evrc_enc_config cfg;
struct msm_audio_evrc_enc_config32 cfg_32;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_EVRC_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.cdma_rate = cfg_32.cdma_rate;
cfg.min_bit_rate = cfg_32.min_bit_rate;
cfg.max_bit_rate = cfg_32.max_bit_rate;
cmd = AUDIO_SET_EVRC_ENC_CONFIG;
rc = evrc_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_EVRC_ENC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#else
#define evrc_in_compat_ioctl NULL
#endif
static int evrc_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_evrc_enc_config *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 23;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->min_bit_rate = 4;
enc_cfg->max_bit_rate = 4;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open evrc encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_EVRC,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: NT mode encoder success\n",
__func__, audio->ac->session);
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_EVRC);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__,
audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: T mode encoder success\n", __func__,
audio->ac->session);
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
audio->reset_event = false;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = evrc_in_compat_ioctl;
audio->enc_ioctl = evrc_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = evrc_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
.compat_ioctl = audio_in_compat_ioctl
};
struct miscdevice audio_evrc_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_evrc_in",
.fops = &audio_in_fops,
};
static int __init evrc_in_init(void)
{
return misc_register(&audio_evrc_in_misc);
}
device_initcall(evrc_in_init);

382
dsp/codecs/g711alaw_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,382 @@
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_g711.h>
#include <linux/atomic.h>
#include <linux/compat.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
static long g711_in_ioctl_shared(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_g711_enc_config *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
rc = q6asm_enc_cfg_blk_g711(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->sample_rate);
if (rc < 0) {
pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
audio->ac->session, audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session,
rc);
break;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG: {
struct msm_audio_g711_enc_config *cfg;
struct msm_audio_g711_enc_config *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
cfg = (struct msm_audio_g711_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer\n", __func__);
rc = -EINVAL;
break;
}
if (cfg->sample_rate != 8000 &&
cfg->sample_rate != 16000) {
pr_err("%s:session id %d: invalid sample rate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
enc_cfg->sample_rate = cfg->sample_rate;
pr_debug("%s:session id %d: sample_rate= 0x%x",
__func__,
audio->ac->session, enc_cfg->sample_rate);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
static long g711_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = g711_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_G711_ENC_CONFIG: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_g711_enc_config))) {
pr_err(
"%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG: {
struct msm_audio_g711_enc_config cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(cfg))) {
pr_err(
"%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
break;
}
rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_g711_enc_config32 {
uint32_t sample_rate;
};
enum {
AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
};
static long g711_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = g711_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_G711_ENC_CONFIG_32: {
struct msm_audio_g711_enc_config32 cfg_32;
struct msm_audio_g711_enc_config32 *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
cfg_32.sample_rate = enc_cfg->sample_rate;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(cfg_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG_32: {
struct msm_audio_g711_enc_config32 cfg_32;
struct msm_audio_g711_enc_config32 cfg;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.sample_rate = cfg_32.sample_rate;
cmd = AUDIO_SET_G711_ENC_CONFIG;
rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
#else
#define g711_in_compat_ioctl NULL
#endif
static int g711_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_g711_enc_config *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/*
* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 320;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->sample_rate = 8000;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open g711 encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_G711_ALAW_FS,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_G711_ALAW_FS);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
audio->reset_event = false;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = g711_in_compat_ioctl;
audio->enc_ioctl = g711_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = g711_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = audio_in_compat_ioctl,
#endif
};
struct miscdevice audio_g711alaw_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_g711alaw_in",
.fops = &audio_in_fops,
};
static int __init g711alaw_in_init(void)
{
return misc_register(&audio_g711alaw_in_misc);
}
device_initcall(g711alaw_in_init);

385
dsp/codecs/g711mlaw_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,385 @@
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_g711.h>
#include <linux/atomic.h>
#include <linux/compat.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
#ifdef CONFIG_COMPAT
#undef PROC_ADD
#endif
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
static long g711_in_ioctl_shared(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_g711_enc_config *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
rc = q6asm_enc_cfg_blk_g711(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->sample_rate);
if (rc < 0) {
pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
audio->ac->session, audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session,
rc);
break;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG: {
struct msm_audio_g711_enc_config *cfg;
struct msm_audio_g711_enc_config *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
cfg = (struct msm_audio_g711_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer\n", __func__);
rc = -EINVAL;
break;
}
if (cfg->sample_rate != 8000 &&
cfg->sample_rate != 16000) {
pr_err("%s:session id %d: invalid sample rate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
enc_cfg->sample_rate = cfg->sample_rate;
pr_debug("%s:session id %d: sample_rate= 0x%x",
__func__,
audio->ac->session, enc_cfg->sample_rate);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
static long g711_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = g711_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_G711_ENC_CONFIG: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_g711_enc_config))) {
pr_err(
"%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG: {
struct msm_audio_g711_enc_config cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(cfg))) {
pr_err(
"%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
break;
}
rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_g711_enc_config32 {
uint32_t sample_rate;
};
enum {
AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
(AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
};
static long g711_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = g711_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_G711_ENC_CONFIG_32: {
struct msm_audio_g711_enc_config32 cfg_32;
struct msm_audio_g711_enc_config32 *enc_cfg;
enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
cfg_32.sample_rate = enc_cfg->sample_rate;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(cfg_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_G711_ENC_CONFIG_32: {
struct msm_audio_g711_enc_config32 cfg_32;
struct msm_audio_g711_enc_config32 cfg;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.sample_rate = cfg_32.sample_rate;
cmd = AUDIO_SET_G711_ENC_CONFIG;
rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -ENOIOCTLCMD;
}
return rc;
}
#else
#define g711_in_compat_ioctl NULL
#endif
static int g711_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_g711_enc_config *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/*
* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 320;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->sample_rate = 8000;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open g711 encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_G711_MLAW_FS,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_G711_MLAW_FS);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
audio->reset_event = false;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = g711_in_compat_ioctl;
audio->enc_ioctl = g711_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = g711_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = audio_in_compat_ioctl,
#endif
};
struct miscdevice audio_g711mlaw_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_g711mlaw_in",
.fops = &audio_in_fops,
};
static int __init g711mlaw_in_init(void)
{
return misc_register(&audio_g711mlaw_in_misc);
}
device_initcall(g711mlaw_in_init);

37
dsp/codecs/q6audio_common.h Arquivo normal
Ver arquivo

@@ -0,0 +1,37 @@
/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
/* For Decoders */
#ifndef __Q6_AUDIO_COMMON_H__
#define __Q6_AUDIO_COMMON_H__
#include <dsp/apr_audio-v2.h>
#include <dsp/q6asm-v2.h>
void q6_audio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv);
void audio_aio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *audio);
/* For Encoders */
void q6asm_in_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv);
void audio_in_get_dsp_frames(void *audio,
uint32_t token, uint32_t *payload);
#endif /*__Q6_AUDIO_COMMON_H__*/

106
dsp/codecs/q6audio_v2.c Arquivo normal
Ver arquivo

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2012-2013, 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
void q6asm_in_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
struct q6audio_in *audio = (struct q6audio_in *)priv;
unsigned long flags;
pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
audio->ac->session, opcode);
spin_lock_irqsave(&audio->dsp_lock, flags);
switch (opcode) {
case ASM_DATA_EVENT_READ_DONE_V2:
audio_in_get_dsp_frames(audio, token, payload);
break;
case ASM_DATA_EVENT_WRITE_DONE_V2:
atomic_inc(&audio->in_count);
wake_up(&audio->write_wait);
break;
case ASM_DATA_EVENT_RENDERED_EOS:
audio->eos_rsp = 1;
wake_up(&audio->read_wait);
break;
case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
break;
case ASM_SESSION_EVENTX_OVERFLOW:
pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
__func__, audio->ac->session);
break;
case RESET_EVENTS:
pr_debug("%s:received RESET EVENTS\n", __func__);
audio->enabled = 0;
audio->stopped = 1;
audio->event_abort = 1;
audio->reset_event = true;
wake_up(&audio->read_wait);
wake_up(&audio->write_wait);
break;
default:
pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
audio->ac->session, opcode);
break;
}
spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
void audio_in_get_dsp_frames(void *priv,
uint32_t token, uint32_t *payload)
{
struct q6audio_in *audio = (struct q6audio_in *)priv;
uint32_t index;
index = q6asm_get_buf_index_from_token(token);
pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
__func__, audio->ac->session, token, payload[9],
payload[5]);
pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
audio->ac->session, payload[7], payload[6]);
pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
audio->ac->session, payload[8], payload[10]);
pr_debug("%s:session id %d: enc_framesotal_size=0x%8x\n", __func__,
audio->ac->session, payload[4]);
/* Ensure the index is within max array size: FRAME_NUM */
if (index >= FRAME_NUM) {
pr_err("%s: Invalid index %d\n",
__func__, index);
return;
}
audio->out_frame_info[index][0] = payload[9];
audio->out_frame_info[index][1] = payload[5];
/* statistics of read */
atomic_add(payload[4], &audio->in_bytes);
atomic_add(payload[9], &audio->in_samples);
if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
atomic_inc(&audio->out_count);
wake_up(&audio->read_wait);
}
}

223
dsp/codecs/q6audio_v2_aio.c Arquivo normal
Ver arquivo

@@ -0,0 +1,223 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils_aio.h"
void q6_audio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
struct q6audio_aio *audio = (struct q6audio_aio *)priv;
pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2:
case ASM_DATA_EVENT_READ_DONE_V2:
case ASM_DATA_EVENT_RENDERED_EOS:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
case RESET_EVENTS:
audio_aio_cb(opcode, token, payload, audio);
break;
default:
pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
break;
}
}
void audio_aio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv/*struct q6audio_aio *audio*/)
{
struct q6audio_aio *audio = (struct q6audio_aio *)priv;
union msm_audio_event_payload e_payload;
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2:
pr_debug("%s[%pK]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
__func__, audio, token);
audio_aio_async_write_ack(audio, token, payload);
break;
case ASM_DATA_EVENT_READ_DONE_V2:
pr_debug("%s[%pK]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
__func__, audio, token);
audio_aio_async_read_ack(audio, token, payload);
break;
case ASM_DATA_EVENT_RENDERED_EOS:
/* EOS Handle */
pr_debug("%s[%pK]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
if (audio->feedback) { /* Non-Tunnel mode */
audio->eos_rsp = 1;
/* propagate input EOS i/p buffer,
* after receiving DSP acknowledgment
*/
if (audio->eos_flag &&
(audio->eos_write_payload.aio_buf.buf_addr)) {
audio_aio_post_event(audio,
AUDIO_EVENT_WRITE_DONE,
audio->eos_write_payload);
memset(&audio->eos_write_payload, 0,
sizeof(union msm_audio_event_payload));
audio->eos_flag = 0;
}
} else { /* Tunnel mode */
audio->eos_rsp = 1;
wake_up(&audio->write_wait);
wake_up(&audio->cmd_wait);
}
break;
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
pr_debug("%s[%pK]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
__func__, audio, payload[0], payload[1], opcode);
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
pr_debug("%s[%pK]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0]-sr = %d, payload[1]-chl = %d, payload[2] = %d, payload[3] = %d\n",
__func__, audio, payload[0],
payload[1], payload[2], payload[3]);
pr_debug("%s[%pK]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
__func__, audio, audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
audio->pcm_cfg.sample_rate = payload[0];
audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
break;
case RESET_EVENTS:
pr_err("%s: Received opcode:0x%x\n", __func__, opcode);
audio->stopped = 1;
audio->reset_event = true;
wake_up(&audio->event_wait);
break;
default:
break;
}
}
void extract_meta_out_info(struct q6audio_aio *audio,
struct audio_aio_buffer_node *buf_node, int dir)
{
struct dec_meta_out *meta_data = buf_node->kvaddr;
uint32_t temp;
if (dir) { /* input buffer - Write */
if (audio->buf_cfg.meta_info_enable)
memcpy(&buf_node->meta_info.meta_in,
(char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
else
memset(&buf_node->meta_info.meta_in,
0, sizeof(struct dec_meta_in));
pr_debug("%s[%pK]:i/p: msw_ts %d lsw_ts %d nflags 0x%8x\n",
__func__, audio,
buf_node->meta_info.meta_in.ntimestamp.highpart,
buf_node->meta_info.meta_in.ntimestamp.lowpart,
buf_node->meta_info.meta_in.nflags);
} else { /* output buffer - Read */
memcpy((char *)buf_node->kvaddr,
&buf_node->meta_info.meta_out,
sizeof(struct dec_meta_out));
meta_data->meta_out_dsp[0].nflags = 0x00000000;
temp = meta_data->meta_out_dsp[0].msw_ts;
meta_data->meta_out_dsp[0].msw_ts =
meta_data->meta_out_dsp[0].lsw_ts;
meta_data->meta_out_dsp[0].lsw_ts = temp;
pr_debug("%s[%pK]:o/p: msw_ts %d lsw_ts %d nflags 0x%8x, num_frames = %d\n",
__func__, audio,
((struct dec_meta_out *)buf_node->kvaddr)->
meta_out_dsp[0].msw_ts,
((struct dec_meta_out *)buf_node->kvaddr)->
meta_out_dsp[0].lsw_ts,
((struct dec_meta_out *)buf_node->kvaddr)->
meta_out_dsp[0].nflags,
((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
}
}
/* Read buffer from DSP / Handle Ack from DSP */
void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload)
{
unsigned long flags;
union msm_audio_event_payload event_payload;
struct audio_aio_buffer_node *filled_buf;
pr_debug("%s\n", __func__);
/* No active flush in progress */
if (audio->rflush)
return;
/* Statistics of read */
atomic_add(payload[4], &audio->in_bytes);
atomic_add(payload[9], &audio->in_samples);
spin_lock_irqsave(&audio->dsp_lock, flags);
if (list_empty(&audio->in_queue)) {
spin_unlock_irqrestore(&audio->dsp_lock, flags);
pr_warn("%s unexpected ack from dsp\n", __func__);
return;
}
filled_buf = list_first_entry(&audio->in_queue,
struct audio_aio_buffer_node, list);
pr_debug("%s token: 0x[%x], filled_buf->token: 0x[%x]",
__func__, token, filled_buf->token);
if (token == (filled_buf->token)) {
list_del(&filled_buf->list);
spin_unlock_irqrestore(&audio->dsp_lock, flags);
event_payload.aio_buf = filled_buf->buf;
/* Read done Buffer due to flush/normal condition
* after EOS event, so append EOS buffer
*/
if (audio->eos_rsp == 0x1) {
event_payload.aio_buf.data_len =
insert_eos_buf(audio, filled_buf);
/* Reset flag back to indicate eos intimated */
audio->eos_rsp = 0;
} else {
filled_buf->meta_info.meta_out.num_of_frames
= payload[9];
event_payload.aio_buf.data_len = payload[4]
+ payload[5] + sizeof(struct dec_meta_out);
pr_debug("%s[%pK]:nr of frames 0x%8x len=%d\n",
__func__, audio,
filled_buf->meta_info.meta_out.num_of_frames,
event_payload.aio_buf.data_len);
extract_meta_out_info(audio, filled_buf, 0);
audio->eos_rsp = 0;
}
pr_debug("%s, posting read done to the app here\n", __func__);
audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
event_payload);
kfree(filled_buf);
} else {
pr_err("%s[%pK]:expected=%x ret=%x\n",
__func__, audio, filled_buf->token, token);
spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
}

410
dsp/codecs/qcelp_in.c Arquivo normal
Ver arquivo

@@ -0,0 +1,410 @@
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_qcp.h>
#include <linux/atomic.h>
#include <linux/compat.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
/* Buffer with meta*/
#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
/* Maximum 10 frames in buffer with meta */
#define FRAME_SIZE (1 + ((35+sizeof(struct meta_out_dsp)) * 10))
static long qcelp_in_ioctl_shared(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
int cnt = 0;
switch (cmd) {
case AUDIO_START: {
struct msm_audio_qcelp_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
audio->ac->session, audio->buf_alloc);
if (audio->enabled == 1) {
pr_info("%s:AUDIO_START already over\n", __func__);
rc = 0;
break;
}
rc = audio_in_buf_alloc(audio);
if (rc < 0) {
pr_err("%s:session id %d: buffer allocation failed\n",
__func__, audio->ac->session);
break;
}
/* reduced_rate_level, rate_modulation_cmd set to zero
* currently not configurable from user space
*/
rc = q6asm_enc_cfg_blk_qcelp(audio->ac,
audio->buf_cfg.frames_per_buf,
enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate, 0, 0);
if (rc < 0) {
pr_err("%s:session id %d: cmd qcelp media format block failed\n",
__func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
rc = q6asm_media_format_block_pcm(audio->ac,
audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
if (rc < 0) {
pr_err("%s:session id %d: media format block failed\n",
__func__, audio->ac->session);
break;
}
}
pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
audio->ac->session, audio->enabled);
rc = audio_in_enable(audio);
if (!rc) {
audio->enabled = 1;
} else {
audio->enabled = 0;
pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
__func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
q6asm_read(audio->ac); /* Push buffer to DSP */
rc = 0;
pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
__func__, audio->ac->session, audio->enabled);
break;
}
case AUDIO_STOP: {
pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
__func__, audio->ac->session,
rc);
break;
}
break;
}
case AUDIO_SET_QCELP_ENC_CONFIG: {
struct msm_audio_qcelp_enc_config *cfg;
struct msm_audio_qcelp_enc_config *enc_cfg;
enc_cfg = audio->enc_cfg;
cfg = (struct msm_audio_qcelp_enc_config *)arg;
if (cfg == NULL) {
pr_err("%s: NULL config pointer\n", __func__);
rc = -EINVAL;
break;
}
if (cfg->min_bit_rate > 4 ||
cfg->min_bit_rate < 1) {
pr_err("%s:session id %d: invalid min bitrate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
if (cfg->max_bit_rate > 4 ||
cfg->max_bit_rate < 1) {
pr_err("%s:session id %d: invalid max bitrate\n",
__func__, audio->ac->session);
rc = -EINVAL;
break;
}
enc_cfg->cdma_rate = cfg->cdma_rate;
enc_cfg->min_bit_rate = cfg->min_bit_rate;
enc_cfg->max_bit_rate = cfg->max_bit_rate;
pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
__func__,
audio->ac->session, enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
static long qcelp_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = qcelp_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_QCELP_ENC_CONFIG: {
if (copy_to_user((void *)arg, audio->enc_cfg,
sizeof(struct msm_audio_qcelp_enc_config))) {
pr_err(
"%s: copy_to_user for AUDIO_GET_QCELP_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_QCELP_ENC_CONFIG: {
struct msm_audio_qcelp_enc_config cfg;
if (copy_from_user(&cfg, (void *) arg,
sizeof(cfg))) {
pr_err(
"%s: copy_from_user for AUDIO_SET_QCELP_ENC_CONFIG failed",
__func__);
rc = -EFAULT;
break;
}
rc = qcelp_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_QCELP_ENC_CONFIG failed. Rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#ifdef CONFIG_COMPAT
struct msm_audio_qcelp_enc_config32 {
u32 cdma_rate;
u32 min_bit_rate;
u32 max_bit_rate;
};
enum {
AUDIO_SET_QCELP_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
0, struct msm_audio_qcelp_enc_config32),
AUDIO_GET_QCELP_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
1, struct msm_audio_qcelp_enc_config32)
};
static long qcelp_in_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct q6audio_in *audio = file->private_data;
int rc = 0;
switch (cmd) {
case AUDIO_START:
case AUDIO_STOP: {
rc = qcelp_in_ioctl_shared(file, cmd, arg);
break;
}
case AUDIO_GET_QCELP_ENC_CONFIG_32: {
struct msm_audio_qcelp_enc_config32 cfg_32;
struct msm_audio_qcelp_enc_config *enc_cfg;
memset(&cfg_32, 0, sizeof(cfg_32));
enc_cfg = (struct msm_audio_qcelp_enc_config *)audio->enc_cfg;
cfg_32.cdma_rate = enc_cfg->cdma_rate;
cfg_32.min_bit_rate = enc_cfg->min_bit_rate;
cfg_32.max_bit_rate = enc_cfg->max_bit_rate;
if (copy_to_user((void *)arg, &cfg_32,
sizeof(cfg_32))) {
pr_err("%s: copy_to_user for AUDIO_GET_QCELP_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
}
break;
}
case AUDIO_SET_QCELP_ENC_CONFIG_32: {
struct msm_audio_qcelp_enc_config32 cfg_32;
struct msm_audio_qcelp_enc_config cfg;
if (copy_from_user(&cfg_32, (void *) arg,
sizeof(cfg_32))) {
pr_err("%s: copy_from_user for AUDIO_SET_QCELP_ENC_CONFIG_32 failed\n",
__func__);
rc = -EFAULT;
break;
}
cfg.cdma_rate = cfg_32.cdma_rate;
cfg.min_bit_rate = cfg_32.min_bit_rate;
cfg.max_bit_rate = cfg_32.max_bit_rate;
cmd = AUDIO_SET_QCELP_ENC_CONFIG;
rc = qcelp_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
if (rc)
pr_err("%s:AUDIO_SET_QCELP_ENC_CONFIG failed. rc= %d\n",
__func__, rc);
break;
}
default:
pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
rc = -EINVAL;
}
return rc;
}
#else
#define qcelp_in_compat_ioctl NULL
#endif
static int qcelp_in_open(struct inode *inode, struct file *file)
{
struct q6audio_in *audio = NULL;
struct msm_audio_qcelp_enc_config *enc_cfg;
int rc = 0;
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL)
return -ENOMEM;
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
kfree(audio);
return -ENOMEM;
}
enc_cfg = audio->enc_cfg;
mutex_init(&audio->lock);
mutex_init(&audio->read_lock);
mutex_init(&audio->write_lock);
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->read_wait);
init_waitqueue_head(&audio->write_wait);
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
*/
audio->str_cfg.buffer_size = FRAME_SIZE;
audio->str_cfg.buffer_count = FRAME_NUM;
audio->min_frame_size = 35;
audio->max_frames_per_buf = 10;
audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
enc_cfg->min_bit_rate = 4;
enc_cfg->max_bit_rate = 4;
audio->pcm_cfg.channel_count = 1;
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
pr_err("%s: Could not allocate memory for audio client\n",
__func__);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
}
/* open qcelp encoder in T/NT mode */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = NON_TUNNEL_MODE;
rc = q6asm_open_read_write(audio->ac, FORMAT_V13K,
FORMAT_LINEAR_PCM);
if (rc < 0) {
pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: NT mode encoder success\n", __func__,
audio->ac->session);
} else if (!(file->f_mode & FMODE_WRITE) &&
(file->f_mode & FMODE_READ)) {
audio->feedback = TUNNEL_MODE;
rc = q6asm_open_read(audio->ac, FORMAT_V13K);
if (rc < 0) {
pr_err("%s:session id %d: T mode Open failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
__func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
pr_info("%s:session id %d: T mode encoder success\n", __func__,
audio->ac->session);
} else {
pr_err("%s:session id %d: Unexpected mode\n", __func__,
audio->ac->session);
rc = -EACCES;
goto fail;
}
audio->opened = 1;
audio->reset_event = false;
atomic_set(&audio->in_count, PCM_BUF_COUNT);
atomic_set(&audio->out_count, 0x00);
audio->enc_compat_ioctl = qcelp_in_compat_ioctl;
audio->enc_ioctl = qcelp_in_ioctl;
file->private_data = audio;
pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
return 0;
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->enc_cfg);
kfree(audio);
return rc;
}
static const struct file_operations audio_in_fops = {
.owner = THIS_MODULE,
.open = qcelp_in_open,
.release = audio_in_release,
.read = audio_in_read,
.write = audio_in_write,
.unlocked_ioctl = audio_in_ioctl,
.compat_ioctl = audio_in_compat_ioctl
};
struct miscdevice audio_qcelp_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_qcelp_in",
.fops = &audio_in_fops,
};
static int __init qcelp_in_init(void)
{
return misc_register(&audio_qcelp_in_misc);
}
device_initcall(qcelp_in_init);