blob: b53edd9a8feb5ca455f2d1dfe42383785e681d5e [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
Sidipotu Ashok4ef84072012-09-13 14:03:25 +05305 * Copyright (c) 2011-2012, 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;
150 if ((aac_config->dual_mono_mode <
151 AUDIO_AAC_DUAL_MONO_PL_PR) ||
152 (aac_config->dual_mono_mode >
153 AUDIO_AAC_DUAL_MONO_PL_SR)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700154 pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
155 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530156 } else {
157 /* convert the data from user into sce_left
158 * and sce_right based on the definitions
159 */
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700160 pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
161 __func__, aac_config->dual_mono_mode);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530162 switch (aac_config->dual_mono_mode) {
163 case AUDIO_AAC_DUAL_MONO_PL_PR:
164 sce_left = 1;
165 sce_right = 1;
166 break;
167 case AUDIO_AAC_DUAL_MONO_SL_SR:
168 sce_left = 2;
169 sce_right = 2;
170 break;
171 case AUDIO_AAC_DUAL_MONO_SL_PR:
172 sce_left = 2;
173 sce_right = 1;
174 break;
175 case AUDIO_AAC_DUAL_MONO_PL_SR:
176 default:
177 sce_left = 1;
178 sce_right = 2;
179 break;
180 }
181 rc = q6asm_cfg_dual_mono_aac(audio->ac,
182 sce_left, sce_right);
183 if (rc < 0)
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700184 pr_err("%s: asm cmd dualmono failed rc=%d\n",
185 __func__, rc);
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530186 } break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 }
188 break;
189 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530191 pr_debug("Calling utils ioctl\n");
192 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 return rc;
195}
196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198static int audio_open(struct inode *inode, struct file *file)
199{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530200 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 int rc = 0;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530202 struct msm_audio_aac_config *aac_config = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203
204#ifdef CONFIG_DEBUG_FS
205 /* 4 bytes represents decoder number, 1 byte for terminate string */
206 char name[sizeof "msm_multi_aac_" + 5];
207#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530208 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209
210 if (audio == NULL) {
211 pr_err("Could not allocate memory for aac decode driver\n");
212 return -ENOMEM;
213 }
214
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530215 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
216 GFP_KERNEL);
217 if (audio->codec_cfg == NULL) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700218 pr_err("%s: Could not allocate memory for aac config\n",
219 __func__);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530220 kfree(audio);
221 return -ENOMEM;
222 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530224 aac_config = audio->codec_cfg;
225
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530226 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530227 aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530228
Harmandeep Singhc35fa07d2012-05-31 07:08:59 -0700229 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 (void *)audio);
231
232 if (!audio->ac) {
233 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530234 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 kfree(audio);
236 return -ENOMEM;
237 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238
239 /* open in T/NT mode */
240 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
241 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700242 FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 if (rc < 0) {
244 pr_err("NT mode Open failed rc=%d\n", rc);
245 rc = -ENODEV;
246 goto fail;
247 }
248 audio->feedback = NON_TUNNEL_MODE;
249 /* open AAC decoder, expected frames is always 1
250 audio->buf_cfg.frames_per_buf = 0x01;*/
251 audio->buf_cfg.meta_info_enable = 0x01;
252 } else if ((file->f_mode & FMODE_WRITE) &&
253 !(file->f_mode & FMODE_READ)) {
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700254 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 if (rc < 0) {
256 pr_err("T mode Open failed rc=%d\n", rc);
257 rc = -ENODEV;
258 goto fail;
259 }
260 audio->feedback = TUNNEL_MODE;
261 audio->buf_cfg.meta_info_enable = 0x00;
262 } else {
263 pr_err("Not supported mode\n");
264 rc = -EACCES;
265 goto fail;
266 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530267 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268
269#ifdef CONFIG_DEBUG_FS
270 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
271 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
272 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530273 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274
275 if (IS_ERR(audio->dentry))
276 pr_debug("debugfs_create_file failed\n");
277#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
279 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530280 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281fail:
282 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530283 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 kfree(audio);
285 return rc;
286}
287
288static const struct file_operations audio_aac_fops = {
289 .owner = THIS_MODULE,
290 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530291 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530293 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294};
295
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530296struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 .minor = MISC_DYNAMIC_MINOR,
298 .name = "msm_multi_aac",
299 .fops = &audio_aac_fops,
300};
301
302static int __init audio_aac_init(void)
303{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530304 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305}
306
307device_initcall(audio_aac_init);