blob: fbd94c5dd8a49031c6952e52eef50a57e1b1d0da [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
Swaminathan Sathappan6f530882012-05-01 16:42:22 -07005 * Copyright (c) 2011-2012, Code Aurora Forum. 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;
46 aac_cfg.ch_cfg = aac_config->channel_configuration;
47 aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053048 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
49 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050 if (audio->feedback == NON_TUNNEL_MODE) {
51 /* Configure PCM output block */
Harmandeep Singheaf59b42012-06-05 21:46:02 -070052 rc = q6asm_enc_cfg_blk_pcm_native(audio->ac,
53 aac_cfg.sample_rate,
54 aac_cfg.ch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055 if (rc < 0) {
56 pr_err("pcm output block config failed\n");
57 break;
58 }
59 }
60 /* turn on both sbr and ps */
61 rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
62 if (rc < 0)
63 pr_err("sbr-ps enable failed\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +053064 if (aac_config->sbr_ps_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053066 else if (aac_config->sbr_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067 aac_cfg.aot = AAC_ENC_MODE_AAC_P;
68 else
69 aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
70
Deepa Madiregama0579ea12011-09-16 04:26:39 +053071 switch (aac_config->format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072 case AUDIO_AAC_FORMAT_ADTS:
73 aac_cfg.format = 0x00;
74 break;
75 case AUDIO_AAC_FORMAT_LOAS:
76 aac_cfg.format = 0x01;
77 break;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053078 case AUDIO_AAC_FORMAT_ADIF:
79 aac_cfg.format = 0x02;
80 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 default:
82 case AUDIO_AAC_FORMAT_RAW:
83 aac_cfg.format = 0x03;
84 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +053085 aac_cfg.ep_config = aac_config->ep_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 aac_cfg.section_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053087 aac_config->aac_section_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 aac_cfg.scalefactor_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053089 aac_config->aac_scalefactor_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090 aac_cfg.spectral_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +053091 aac_config->aac_spectral_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
93 pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
94 __func__, aac_cfg.format,
95 aac_cfg.aot, aac_cfg.ch_cfg,
96 aac_cfg.sample_rate);
97
98 /* Configure Media format block */
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -070099 rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100 if (rc < 0) {
101 pr_err("cmd media format block failed\n");
102 break;
103 }
Swaminathan Sathappan6f530882012-05-01 16:42:22 -0700104 if (!cpu_is_msm8x60()) {
105 rc = q6asm_set_encdec_chan_map(audio->ac, 2);
106 if (rc < 0) {
107 pr_err("%s: cmd set encdec_chan_map failed\n",
108 __func__);
109 break;
110 }
111 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530112 rc = audio_aio_enable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700113 audio->eos_rsp = 0;
114 audio->eos_flag = 0;
115 if (!rc) {
116 audio->enabled = 1;
117 } else {
118 audio->enabled = 0;
119 pr_err("Audio Start procedure failed rc=%d\n", rc);
120 break;
121 }
122 pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
123 audio->ac->session,
124 audio->enabled);
125 if (audio->stopped == 1)
126 audio->stopped = 0;
127 break;
128 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 case AUDIO_GET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530130 if (copy_to_user((void *)arg, audio->codec_cfg,
131 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 rc = -EFAULT;
133 break;
134 }
135 break;
136 }
137 case AUDIO_SET_AAC_CONFIG: {
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530138 struct msm_audio_aac_config *aac_config;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530139 if (copy_from_user(audio->codec_cfg, (void *)arg,
140 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 rc = -EFAULT;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530142 } else {
143 uint16_t sce_left = 1, sce_right = 2;
144 aac_config = audio->codec_cfg;
145 if ((aac_config->dual_mono_mode <
146 AUDIO_AAC_DUAL_MONO_PL_PR) ||
147 (aac_config->dual_mono_mode >
148 AUDIO_AAC_DUAL_MONO_PL_SR)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700149 pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
150 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530151 } else {
152 /* convert the data from user into sce_left
153 * and sce_right based on the definitions
154 */
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700155 pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
156 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530157 switch (aac_config->dual_mono_mode) {
158 case AUDIO_AAC_DUAL_MONO_PL_PR:
159 sce_left = 1;
160 sce_right = 1;
161 break;
162 case AUDIO_AAC_DUAL_MONO_SL_SR:
163 sce_left = 2;
164 sce_right = 2;
165 break;
166 case AUDIO_AAC_DUAL_MONO_SL_PR:
167 sce_left = 2;
168 sce_right = 1;
169 break;
170 case AUDIO_AAC_DUAL_MONO_PL_SR:
171 default:
172 sce_left = 1;
173 sce_right = 2;
174 break;
175 }
176 rc = q6asm_cfg_dual_mono_aac(audio->ac,
177 sce_left, sce_right);
178 if (rc < 0)
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700179 pr_err("%s: asm cmd dualmono failed rc=%d\n",
180 __func__, rc);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530181 } break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 }
183 break;
184 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530186 pr_debug("Calling utils ioctl\n");
187 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 return rc;
190}
191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192
193static int audio_open(struct inode *inode, struct file *file)
194{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530195 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 int rc = 0;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530197 struct msm_audio_aac_config *aac_config = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198
199#ifdef CONFIG_DEBUG_FS
200 /* 4 bytes represents decoder number, 1 byte for terminate string */
201 char name[sizeof "msm_multi_aac_" + 5];
202#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530203 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204
205 if (audio == NULL) {
206 pr_err("Could not allocate memory for aac decode driver\n");
207 return -ENOMEM;
208 }
209
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530210 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
211 GFP_KERNEL);
212 if (audio->codec_cfg == NULL) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700213 pr_err("%s: Could not allocate memory for aac config\n",
214 __func__);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530215 kfree(audio);
216 return -ENOMEM;
217 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530219 aac_config = audio->codec_cfg;
220
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530221 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530222 aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530223
Harmandeep Singhc35fa07d2012-05-31 07:08:59 -0700224 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 (void *)audio);
226
227 if (!audio->ac) {
228 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530229 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 kfree(audio);
231 return -ENOMEM;
232 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233
234 /* open in T/NT mode */
235 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
236 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700237 FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238 if (rc < 0) {
239 pr_err("NT mode Open failed rc=%d\n", rc);
240 rc = -ENODEV;
241 goto fail;
242 }
243 audio->feedback = NON_TUNNEL_MODE;
244 /* open AAC decoder, expected frames is always 1
245 audio->buf_cfg.frames_per_buf = 0x01;*/
246 audio->buf_cfg.meta_info_enable = 0x01;
247 } else if ((file->f_mode & FMODE_WRITE) &&
248 !(file->f_mode & FMODE_READ)) {
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700249 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 if (rc < 0) {
251 pr_err("T mode Open failed rc=%d\n", rc);
252 rc = -ENODEV;
253 goto fail;
254 }
255 audio->feedback = TUNNEL_MODE;
256 audio->buf_cfg.meta_info_enable = 0x00;
257 } else {
258 pr_err("Not supported mode\n");
259 rc = -EACCES;
260 goto fail;
261 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530262 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263
264#ifdef CONFIG_DEBUG_FS
265 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
266 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
267 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530268 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269
270 if (IS_ERR(audio->dentry))
271 pr_debug("debugfs_create_file failed\n");
272#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
274 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530275 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276fail:
277 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530278 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 kfree(audio);
280 return rc;
281}
282
283static const struct file_operations audio_aac_fops = {
284 .owner = THIS_MODULE,
285 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530286 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530288 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289};
290
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530291struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 .minor = MISC_DYNAMIC_MINOR,
293 .name = "msm_multi_aac",
294 .fops = &audio_aac_fops,
295};
296
297static int __init audio_aac_init(void)
298{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530299 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300}
301
302device_initcall(audio_aac_init);