blob: 658c07b4823fd7a2c368d454c9de8cbf0ab87fe4 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* aac audio output device
2 *
3 * Copyright (C) 2008 Google, Inc.
4 * Copyright (C) 2008 HTC Corporation
Patrick Lai38d61372013-01-05 21:46:38 -08005 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <linux/msm_audio_aac.h>
Swaminathan Sathappan6f530882012-05-01 16:42:22 -070019#include <mach/socinfo.h>
Deepa Madiregama0579ea12011-09-16 04:26:39 +053020#include "audio_utils_aio.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021
Sidipotu Ashok4513b092011-10-20 09:11:01 +053022#define AUDIO_AAC_DUAL_MONO_INVALID -1
23
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
25/* Default number of pre-allocated event packets */
Deepa Madiregama0579ea12011-09-16 04:26:39 +053026#define PCM_BUFSZ_MIN_AACM ((8*1024) + sizeof(struct dec_meta_out))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#ifdef CONFIG_DEBUG_FS
Deepa Madiregama0579ea12011-09-16 04:26:39 +053029static const struct file_operations audio_aac_debug_fops = {
30 .read = audio_aio_debug_read,
31 .open = audio_aio_debug_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032};
33#endif
34
35static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
36{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053037 struct q6audio_aio *audio = file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038 int rc = 0;
39
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 switch (cmd) {
41 case AUDIO_START: {
42 struct asm_aac_cfg aac_cfg;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053043 struct msm_audio_aac_config *aac_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044 uint32_t sbr_ps = 0x00;
Harmandeep Singheaf59b42012-06-05 21:46:02 -070045 aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
Sidipotu Ashok4ef84072012-09-13 14:03:25 +053046 if (audio->feedback == TUNNEL_MODE) {
47 aac_cfg.sample_rate = aac_config->sample_rate;
48 aac_cfg.ch_cfg = aac_config->channel_configuration;
49 } else {
50 aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
51 aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
52 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +053053 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
54 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055 if (audio->feedback == NON_TUNNEL_MODE) {
56 /* Configure PCM output block */
Harmandeep Singheaf59b42012-06-05 21:46:02 -070057 rc = q6asm_enc_cfg_blk_pcm_native(audio->ac,
58 aac_cfg.sample_rate,
59 aac_cfg.ch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060 if (rc < 0) {
61 pr_err("pcm output block config failed\n");
62 break;
63 }
64 }
65 /* turn on both sbr and ps */
66 rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
67 if (rc < 0)
68 pr_err("sbr-ps enable failed\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +053069 if (aac_config->sbr_ps_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053071 else if (aac_config->sbr_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072 aac_cfg.aot = AAC_ENC_MODE_AAC_P;
73 else
74 aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
75
Deepa Madiregama0579ea12011-09-16 04:26:39 +053076 switch (aac_config->format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077 case AUDIO_AAC_FORMAT_ADTS:
78 aac_cfg.format = 0x00;
79 break;
80 case AUDIO_AAC_FORMAT_LOAS:
81 aac_cfg.format = 0x01;
82 break;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053083 case AUDIO_AAC_FORMAT_ADIF:
84 aac_cfg.format = 0x02;
85 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 default:
87 case AUDIO_AAC_FORMAT_RAW:
88 aac_cfg.format = 0x03;
89 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +053090 aac_cfg.ep_config = aac_config->ep_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 aac_cfg.section_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053092 aac_config->aac_section_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 aac_cfg.scalefactor_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053094 aac_config->aac_scalefactor_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070095 aac_cfg.spectral_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053096 aac_config->aac_spectral_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097
98 pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
99 __func__, aac_cfg.format,
100 aac_cfg.aot, aac_cfg.ch_cfg,
101 aac_cfg.sample_rate);
102
103 /* Configure Media format block */
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700104 rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 if (rc < 0) {
106 pr_err("cmd media format block failed\n");
107 break;
108 }
Swaminathan Sathappan6f530882012-05-01 16:42:22 -0700109 if (!cpu_is_msm8x60()) {
110 rc = q6asm_set_encdec_chan_map(audio->ac, 2);
111 if (rc < 0) {
112 pr_err("%s: cmd set encdec_chan_map failed\n",
113 __func__);
114 break;
115 }
116 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530117 rc = audio_aio_enable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118 audio->eos_rsp = 0;
119 audio->eos_flag = 0;
120 if (!rc) {
121 audio->enabled = 1;
122 } else {
123 audio->enabled = 0;
124 pr_err("Audio Start procedure failed rc=%d\n", rc);
125 break;
126 }
127 pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
128 audio->ac->session,
129 audio->enabled);
130 if (audio->stopped == 1)
131 audio->stopped = 0;
132 break;
133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 case AUDIO_GET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530135 if (copy_to_user((void *)arg, audio->codec_cfg,
136 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 rc = -EFAULT;
138 break;
139 }
140 break;
141 }
142 case AUDIO_SET_AAC_CONFIG: {
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530143 struct msm_audio_aac_config *aac_config;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530144 if (copy_from_user(audio->codec_cfg, (void *)arg,
145 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146 rc = -EFAULT;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530147 } else {
148 uint16_t sce_left = 1, sce_right = 2;
149 aac_config = audio->codec_cfg;
Patrick Lai38d61372013-01-05 21:46:38 -0800150 if (aac_config->dual_mono_mode >
151 AUDIO_AAC_DUAL_MONO_PL_SR) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700152 pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
153 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530154 } else {
155 /* convert the data from user into sce_left
156 * and sce_right based on the definitions
157 */
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700158 pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
159 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530160 switch (aac_config->dual_mono_mode) {
161 case AUDIO_AAC_DUAL_MONO_PL_PR:
162 sce_left = 1;
163 sce_right = 1;
164 break;
165 case AUDIO_AAC_DUAL_MONO_SL_SR:
166 sce_left = 2;
167 sce_right = 2;
168 break;
169 case AUDIO_AAC_DUAL_MONO_SL_PR:
170 sce_left = 2;
171 sce_right = 1;
172 break;
173 case AUDIO_AAC_DUAL_MONO_PL_SR:
174 default:
175 sce_left = 1;
176 sce_right = 2;
177 break;
178 }
179 rc = q6asm_cfg_dual_mono_aac(audio->ac,
180 sce_left, sce_right);
181 if (rc < 0)
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700182 pr_err("%s: asm cmd dualmono failed rc=%d\n",
183 __func__, rc);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530184 } break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 }
186 break;
187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530189 pr_debug("Calling utils ioctl\n");
190 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 return rc;
193}
194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195
196static int audio_open(struct inode *inode, struct file *file)
197{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530198 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 int rc = 0;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530200 struct msm_audio_aac_config *aac_config = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201
202#ifdef CONFIG_DEBUG_FS
203 /* 4 bytes represents decoder number, 1 byte for terminate string */
204 char name[sizeof "msm_multi_aac_" + 5];
205#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530206 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207
208 if (audio == NULL) {
209 pr_err("Could not allocate memory for aac decode driver\n");
210 return -ENOMEM;
211 }
212
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530213 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
214 GFP_KERNEL);
215 if (audio->codec_cfg == NULL) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700216 pr_err("%s: Could not allocate memory for aac config\n",
217 __func__);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530218 kfree(audio);
219 return -ENOMEM;
220 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530222 aac_config = audio->codec_cfg;
223
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530224 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530225 aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530226
Harmandeep Singhc35fa07d2012-05-31 07:08:59 -0700227 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 (void *)audio);
229
230 if (!audio->ac) {
231 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530232 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 kfree(audio);
234 return -ENOMEM;
235 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236
237 /* open in T/NT mode */
238 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
239 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700240 FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 if (rc < 0) {
242 pr_err("NT mode Open failed rc=%d\n", rc);
243 rc = -ENODEV;
244 goto fail;
245 }
246 audio->feedback = NON_TUNNEL_MODE;
247 /* open AAC decoder, expected frames is always 1
248 audio->buf_cfg.frames_per_buf = 0x01;*/
249 audio->buf_cfg.meta_info_enable = 0x01;
250 } else if ((file->f_mode & FMODE_WRITE) &&
251 !(file->f_mode & FMODE_READ)) {
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700252 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 if (rc < 0) {
254 pr_err("T mode Open failed rc=%d\n", rc);
255 rc = -ENODEV;
256 goto fail;
257 }
258 audio->feedback = TUNNEL_MODE;
259 audio->buf_cfg.meta_info_enable = 0x00;
260 } else {
261 pr_err("Not supported mode\n");
262 rc = -EACCES;
263 goto fail;
264 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530265 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266
267#ifdef CONFIG_DEBUG_FS
268 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
269 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
270 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530271 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272
273 if (IS_ERR(audio->dentry))
274 pr_debug("debugfs_create_file failed\n");
275#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
277 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530278 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279fail:
280 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530281 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 kfree(audio);
283 return rc;
284}
285
286static const struct file_operations audio_aac_fops = {
287 .owner = THIS_MODULE,
288 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530289 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530291 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292};
293
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530294struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 .minor = MISC_DYNAMIC_MINOR,
296 .name = "msm_multi_aac",
297 .fops = &audio_aac_fops,
298};
299
300static int __init audio_aac_init(void)
301{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530302 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303}
304
305device_initcall(audio_aac_init);