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:
5
dsp/codecs/Makefile
Arquivo normal
5
dsp/codecs/Makefile
Arquivo normal
@@ -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
709
dsp/codecs/aac_in.c
Arquivo normal
@@ -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
402
dsp/codecs/amrnb_in.c
Arquivo normal
@@ -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
400
dsp/codecs/amrwb_in.c
Arquivo normal
@@ -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
474
dsp/codecs/audio_aac.c
Arquivo normal
@@ -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
435
dsp/codecs/audio_alac.c
Arquivo normal
@@ -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
226
dsp/codecs/audio_amrnb.c
Arquivo normal
@@ -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
231
dsp/codecs/audio_amrwb.c
Arquivo normal
@@ -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
397
dsp/codecs/audio_amrwbplus.c
Arquivo normal
@@ -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
359
dsp/codecs/audio_ape.c
Arquivo normal
@@ -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
184
dsp/codecs/audio_evrc.c
Arquivo normal
@@ -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
396
dsp/codecs/audio_g711alaw.c
Arquivo normal
@@ -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
396
dsp/codecs/audio_g711mlaw.c
Arquivo normal
@@ -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);
|
778
dsp/codecs/audio_hwacc_effects.c
Arquivo normal
778
dsp/codecs/audio_hwacc_effects.c
Arquivo normal
@@ -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
188
dsp/codecs/audio_mp3.c
Arquivo normal
@@ -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
523
dsp/codecs/audio_multi_aac.c
Arquivo normal
@@ -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
191
dsp/codecs/audio_qcelp.c
Arquivo normal
@@ -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
954
dsp/codecs/audio_utils.c
Arquivo normal
@@ -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
114
dsp/codecs/audio_utils.h
Arquivo normal
@@ -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
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
232
dsp/codecs/audio_utils_aio.h
Arquivo normal
@@ -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
345
dsp/codecs/audio_wma.c
Arquivo normal
@@ -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
418
dsp/codecs/audio_wmapro.c
Arquivo normal
@@ -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
410
dsp/codecs/evrc_in.c
Arquivo normal
@@ -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
382
dsp/codecs/g711alaw_in.c
Arquivo normal
@@ -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
385
dsp/codecs/g711mlaw_in.c
Arquivo normal
@@ -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
37
dsp/codecs/q6audio_common.h
Arquivo normal
@@ -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
106
dsp/codecs/q6audio_v2.c
Arquivo normal
@@ -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
223
dsp/codecs/q6audio_v2_aio.c
Arquivo normal
@@ -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
410
dsp/codecs/qcelp_in.c
Arquivo normal
@@ -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);
|
Referência em uma nova issue
Block a user