blob: 75af8810f01655a6dcafb451dc7d58cdb4fc6b11 [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
5 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
6 *
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>
Deepa Madiregama0579ea12011-09-16 04:26:39 +053019#include "audio_utils_aio.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
Sidipotu Ashok4513b092011-10-20 09:11:01 +053021#define AUDIO_AAC_DUAL_MONO_INVALID -1
22
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023
24/* Default number of pre-allocated event packets */
Deepa Madiregama0579ea12011-09-16 04:26:39 +053025#define PCM_BUFSZ_MIN_AACM ((8*1024) + sizeof(struct dec_meta_out))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
Deepa Madiregama0579ea12011-09-16 04:26:39 +053027static void q6_audio_aac_cb(uint32_t opcode, uint32_t token,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028 uint32_t *payload, void *priv)
29{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053030 struct q6audio_aio *audio = (struct q6audio_aio *)priv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
Deepa Madiregama0579ea12011-09-16 04:26:39 +053032 pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033 switch (opcode) {
34 case ASM_DATA_EVENT_WRITE_DONE:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035 case ASM_DATA_EVENT_READ_DONE:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036 case ASM_DATA_CMDRSP_EOS:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037 case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
38 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
Sidipotu Ashokbe2a8172011-10-20 09:04:35 +053040 case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
Deepa Madiregama0579ea12011-09-16 04:26:39 +053041 audio_aio_cb(opcode, token, payload, audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042 break;
43 default:
44 pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
45 break;
46 }
47}
48
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049#ifdef CONFIG_DEBUG_FS
Deepa Madiregama0579ea12011-09-16 04:26:39 +053050static const struct file_operations audio_aac_debug_fops = {
51 .read = audio_aio_debug_read,
52 .open = audio_aio_debug_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053};
54#endif
55
56static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
57{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053058 struct q6audio_aio *audio = file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059 int rc = 0;
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061 switch (cmd) {
62 case AUDIO_START: {
63 struct asm_aac_cfg aac_cfg;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053064 struct msm_audio_aac_config *aac_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065 uint32_t sbr_ps = 0x00;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053066 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
67 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068 if (audio->feedback == NON_TUNNEL_MODE) {
69 /* Configure PCM output block */
70 rc = q6asm_enc_cfg_blk_pcm(audio->ac,
Sidipotu Ashokbe2a8172011-10-20 09:04:35 +053071 0, /*native sampling rate*/
72 (audio->pcm_cfg.channel_count <= 2) ? 0 : 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073 if (rc < 0) {
74 pr_err("pcm output block config failed\n");
75 break;
76 }
77 }
78 /* turn on both sbr and ps */
79 rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
80 if (rc < 0)
81 pr_err("sbr-ps enable failed\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +053082 aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
83 if (aac_config->sbr_ps_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053085 else if (aac_config->sbr_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 aac_cfg.aot = AAC_ENC_MODE_AAC_P;
87 else
88 aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
89
Deepa Madiregama0579ea12011-09-16 04:26:39 +053090 switch (aac_config->format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 case AUDIO_AAC_FORMAT_ADTS:
92 aac_cfg.format = 0x00;
93 break;
94 case AUDIO_AAC_FORMAT_LOAS:
95 aac_cfg.format = 0x01;
96 break;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053097 case AUDIO_AAC_FORMAT_ADIF:
98 aac_cfg.format = 0x02;
99 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100 default:
101 case AUDIO_AAC_FORMAT_RAW:
102 aac_cfg.format = 0x03;
103 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530104 aac_cfg.ep_config = aac_config->ep_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 aac_cfg.section_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530106 aac_config->aac_section_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 aac_cfg.scalefactor_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530108 aac_config->aac_scalefactor_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 aac_cfg.spectral_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530110 aac_config->aac_spectral_data_resilience_flag;
111 aac_cfg.ch_cfg = aac_config->channel_configuration;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112 aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
113
114 pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
115 __func__, aac_cfg.format,
116 aac_cfg.aot, aac_cfg.ch_cfg,
117 aac_cfg.sample_rate);
118
119 /* Configure Media format block */
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700120 rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 if (rc < 0) {
122 pr_err("cmd media format block failed\n");
123 break;
124 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530125 rc = audio_aio_enable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 audio->eos_rsp = 0;
127 audio->eos_flag = 0;
128 if (!rc) {
129 audio->enabled = 1;
130 } else {
131 audio->enabled = 0;
132 pr_err("Audio Start procedure failed rc=%d\n", rc);
133 break;
134 }
135 pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
136 audio->ac->session,
137 audio->enabled);
138 if (audio->stopped == 1)
139 audio->stopped = 0;
140 break;
141 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 case AUDIO_GET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530143 if (copy_to_user((void *)arg, audio->codec_cfg,
144 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 rc = -EFAULT;
146 break;
147 }
148 break;
149 }
150 case AUDIO_SET_AAC_CONFIG: {
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530151 struct msm_audio_aac_config *aac_config;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530152 if (copy_from_user(audio->codec_cfg, (void *)arg,
153 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 rc = -EFAULT;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530155 } else {
156 uint16_t sce_left = 1, sce_right = 2;
157 aac_config = audio->codec_cfg;
158 if ((aac_config->dual_mono_mode <
159 AUDIO_AAC_DUAL_MONO_PL_PR) ||
160 (aac_config->dual_mono_mode >
161 AUDIO_AAC_DUAL_MONO_PL_SR)) {
162 pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid"
163 "dual_mono mode =%d\n", __func__,
164 aac_config->dual_mono_mode);
165 } else {
166 /* convert the data from user into sce_left
167 * and sce_right based on the definitions
168 */
169 pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify"
170 "dual_mono mode =%d\n", __func__,
171 aac_config->dual_mono_mode);
172 switch (aac_config->dual_mono_mode) {
173 case AUDIO_AAC_DUAL_MONO_PL_PR:
174 sce_left = 1;
175 sce_right = 1;
176 break;
177 case AUDIO_AAC_DUAL_MONO_SL_SR:
178 sce_left = 2;
179 sce_right = 2;
180 break;
181 case AUDIO_AAC_DUAL_MONO_SL_PR:
182 sce_left = 2;
183 sce_right = 1;
184 break;
185 case AUDIO_AAC_DUAL_MONO_PL_SR:
186 default:
187 sce_left = 1;
188 sce_right = 2;
189 break;
190 }
191 rc = q6asm_cfg_dual_mono_aac(audio->ac,
192 sce_left, sce_right);
193 if (rc < 0)
194 pr_err("%s: asm cmd dualmono failed"
195 " rc=%d\n", __func__, rc);
196 } break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 }
198 break;
199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530201 pr_debug("Calling utils ioctl\n");
202 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 return rc;
205}
206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207
208static int audio_open(struct inode *inode, struct file *file)
209{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530210 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 int rc = 0;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530212 struct msm_audio_aac_config *aac_config = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
214#ifdef CONFIG_DEBUG_FS
215 /* 4 bytes represents decoder number, 1 byte for terminate string */
216 char name[sizeof "msm_multi_aac_" + 5];
217#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530218 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219
220 if (audio == NULL) {
221 pr_err("Could not allocate memory for aac decode driver\n");
222 return -ENOMEM;
223 }
224
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530225 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
226 GFP_KERNEL);
227 if (audio->codec_cfg == NULL) {
228 pr_err("%s: Could not allocate memory for aac\
229 config\n", __func__);
230 kfree(audio);
231 return -ENOMEM;
232 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530234 aac_config = audio->codec_cfg;
235
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530236 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
Sidipotu Ashok4513b092011-10-20 09:11:01 +0530237 aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530238
239 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_aac_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 (void *)audio);
241
242 if (!audio->ac) {
243 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530244 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 kfree(audio);
246 return -ENOMEM;
247 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248
249 /* open in T/NT mode */
250 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
251 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700252 FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 if (rc < 0) {
254 pr_err("NT mode Open failed rc=%d\n", rc);
255 rc = -ENODEV;
256 goto fail;
257 }
258 audio->feedback = NON_TUNNEL_MODE;
259 /* open AAC decoder, expected frames is always 1
260 audio->buf_cfg.frames_per_buf = 0x01;*/
261 audio->buf_cfg.meta_info_enable = 0x01;
262 } else if ((file->f_mode & FMODE_WRITE) &&
263 !(file->f_mode & FMODE_READ)) {
Bharath Ramachandramurthy4f71d502011-10-23 19:45:22 -0700264 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 if (rc < 0) {
266 pr_err("T mode Open failed rc=%d\n", rc);
267 rc = -ENODEV;
268 goto fail;
269 }
270 audio->feedback = TUNNEL_MODE;
271 audio->buf_cfg.meta_info_enable = 0x00;
272 } else {
273 pr_err("Not supported mode\n");
274 rc = -EACCES;
275 goto fail;
276 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530277 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278
279#ifdef CONFIG_DEBUG_FS
280 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
281 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
282 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530283 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284
285 if (IS_ERR(audio->dentry))
286 pr_debug("debugfs_create_file failed\n");
287#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
289 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530290 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291fail:
292 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530293 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 kfree(audio);
295 return rc;
296}
297
298static const struct file_operations audio_aac_fops = {
299 .owner = THIS_MODULE,
300 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530301 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530303 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304};
305
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530306struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 .minor = MISC_DYNAMIC_MINOR,
308 .name = "msm_multi_aac",
309 .fops = &audio_aac_fops,
310};
311
312static int __init audio_aac_init(void)
313{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530314 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315}
316
317device_initcall(audio_aac_init);