blob: 553a2e4fd5b53a0f3f411ab964eb2db404fb3f23 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021
22/* Default number of pre-allocated event packets */
Deepa Madiregama0579ea12011-09-16 04:26:39 +053023#define PCM_BUFSZ_MIN_AACM ((8*1024) + sizeof(struct dec_meta_out))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
Deepa Madiregama0579ea12011-09-16 04:26:39 +053025static void q6_audio_aac_cb(uint32_t opcode, uint32_t token,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026 uint32_t *payload, void *priv)
27{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053028 struct q6audio_aio *audio = (struct q6audio_aio *)priv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
Deepa Madiregama0579ea12011-09-16 04:26:39 +053030 pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031 switch (opcode) {
32 case ASM_DATA_EVENT_WRITE_DONE:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033 case ASM_DATA_EVENT_READ_DONE:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034 case ASM_DATA_CMDRSP_EOS:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035 case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
36 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
Deepa Madiregama0579ea12011-09-16 04:26:39 +053038 audio_aio_cb(opcode, token, payload, audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039 break;
40 default:
41 pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
42 break;
43 }
44}
45
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#ifdef CONFIG_DEBUG_FS
Deepa Madiregama0579ea12011-09-16 04:26:39 +053047static const struct file_operations audio_aac_debug_fops = {
48 .read = audio_aio_debug_read,
49 .open = audio_aio_debug_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050};
51#endif
52
53static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
54{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053055 struct q6audio_aio *audio = file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056 int rc = 0;
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058 switch (cmd) {
59 case AUDIO_START: {
60 struct asm_aac_cfg aac_cfg;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053061 struct msm_audio_aac_config *aac_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062 uint32_t sbr_ps = 0x00;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053063 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
64 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065 if (audio->feedback == NON_TUNNEL_MODE) {
66 /* Configure PCM output block */
67 rc = q6asm_enc_cfg_blk_pcm(audio->ac,
68 audio->pcm_cfg.sample_rate,
69 audio->pcm_cfg.channel_count);
70 if (rc < 0) {
71 pr_err("pcm output block config failed\n");
72 break;
73 }
74 }
75 /* turn on both sbr and ps */
76 rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
77 if (rc < 0)
78 pr_err("sbr-ps enable failed\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +053079 aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
80 if (aac_config->sbr_ps_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053082 else if (aac_config->sbr_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083 aac_cfg.aot = AAC_ENC_MODE_AAC_P;
84 else
85 aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
86
Deepa Madiregama0579ea12011-09-16 04:26:39 +053087 switch (aac_config->format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 case AUDIO_AAC_FORMAT_ADTS:
89 aac_cfg.format = 0x00;
90 break;
91 case AUDIO_AAC_FORMAT_LOAS:
92 aac_cfg.format = 0x01;
93 break;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053094 case AUDIO_AAC_FORMAT_ADIF:
95 aac_cfg.format = 0x02;
96 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 default:
98 case AUDIO_AAC_FORMAT_RAW:
99 aac_cfg.format = 0x03;
100 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530101 aac_cfg.ep_config = aac_config->ep_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 aac_cfg.section_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530103 aac_config->aac_section_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104 aac_cfg.scalefactor_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530105 aac_config->aac_scalefactor_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106 aac_cfg.spectral_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530107 aac_config->aac_spectral_data_resilience_flag;
108 aac_cfg.ch_cfg = aac_config->channel_configuration;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
110
111 pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
112 __func__, aac_cfg.format,
113 aac_cfg.aot, aac_cfg.ch_cfg,
114 aac_cfg.sample_rate);
115
116 /* Configure Media format block */
117 rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
118 if (rc < 0) {
119 pr_err("cmd media format block failed\n");
120 break;
121 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530122 rc = audio_aio_enable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 audio->eos_rsp = 0;
124 audio->eos_flag = 0;
125 if (!rc) {
126 audio->enabled = 1;
127 } else {
128 audio->enabled = 0;
129 pr_err("Audio Start procedure failed rc=%d\n", rc);
130 break;
131 }
132 pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
133 audio->ac->session,
134 audio->enabled);
135 if (audio->stopped == 1)
136 audio->stopped = 0;
137 break;
138 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 case AUDIO_GET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530140 if (copy_to_user((void *)arg, audio->codec_cfg,
141 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 rc = -EFAULT;
143 break;
144 }
145 break;
146 }
147 case AUDIO_SET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530148 if (copy_from_user(audio->codec_cfg, (void *)arg,
149 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 rc = -EFAULT;
151 break;
152 }
153 break;
154 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530156 pr_debug("Calling utils ioctl\n");
157 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 return rc;
160}
161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162
163static int audio_open(struct inode *inode, struct file *file)
164{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530165 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167
168#ifdef CONFIG_DEBUG_FS
169 /* 4 bytes represents decoder number, 1 byte for terminate string */
170 char name[sizeof "msm_multi_aac_" + 5];
171#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530172 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173
174 if (audio == NULL) {
175 pr_err("Could not allocate memory for aac decode driver\n");
176 return -ENOMEM;
177 }
178
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530179 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
180 GFP_KERNEL);
181 if (audio->codec_cfg == NULL) {
182 pr_err("%s: Could not allocate memory for aac\
183 config\n", __func__);
184 kfree(audio);
185 return -ENOMEM;
186 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530188 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
189
190 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_aac_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 (void *)audio);
192
193 if (!audio->ac) {
194 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530195 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 kfree(audio);
197 return -ENOMEM;
198 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199
200 /* open in T/NT mode */
201 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
202 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
203 FORMAT_MPEG4_AAC);
204 if (rc < 0) {
205 pr_err("NT mode Open failed rc=%d\n", rc);
206 rc = -ENODEV;
207 goto fail;
208 }
209 audio->feedback = NON_TUNNEL_MODE;
210 /* open AAC decoder, expected frames is always 1
211 audio->buf_cfg.frames_per_buf = 0x01;*/
212 audio->buf_cfg.meta_info_enable = 0x01;
213 } else if ((file->f_mode & FMODE_WRITE) &&
214 !(file->f_mode & FMODE_READ)) {
215 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
216 if (rc < 0) {
217 pr_err("T mode Open failed rc=%d\n", rc);
218 rc = -ENODEV;
219 goto fail;
220 }
221 audio->feedback = TUNNEL_MODE;
222 audio->buf_cfg.meta_info_enable = 0x00;
223 } else {
224 pr_err("Not supported mode\n");
225 rc = -EACCES;
226 goto fail;
227 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530228 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229
230#ifdef CONFIG_DEBUG_FS
231 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
232 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
233 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530234 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235
236 if (IS_ERR(audio->dentry))
237 pr_debug("debugfs_create_file failed\n");
238#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
240 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530241 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242fail:
243 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530244 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 kfree(audio);
246 return rc;
247}
248
249static const struct file_operations audio_aac_fops = {
250 .owner = THIS_MODULE,
251 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530252 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530254 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255};
256
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530257struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 .minor = MISC_DYNAMIC_MINOR,
259 .name = "msm_multi_aac",
260 .fops = &audio_aac_fops,
261};
262
263static int __init audio_aac_init(void)
264{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530265 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266}
267
268device_initcall(audio_aac_init);