blob: 122634f72636ebfd042311aa1a6333a7d4f052cd [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:
Sidipotu Ashokbe2a8172011-10-20 09:04:35 +053038 case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
Deepa Madiregama0579ea12011-09-16 04:26:39 +053039 audio_aio_cb(opcode, token, payload, audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 break;
41 default:
42 pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
43 break;
44 }
45}
46
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#ifdef CONFIG_DEBUG_FS
Deepa Madiregama0579ea12011-09-16 04:26:39 +053048static const struct file_operations audio_aac_debug_fops = {
49 .read = audio_aio_debug_read,
50 .open = audio_aio_debug_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051};
52#endif
53
54static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
55{
Deepa Madiregama0579ea12011-09-16 04:26:39 +053056 struct q6audio_aio *audio = file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057 int rc = 0;
58
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059 switch (cmd) {
60 case AUDIO_START: {
61 struct asm_aac_cfg aac_cfg;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053062 struct msm_audio_aac_config *aac_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063 uint32_t sbr_ps = 0x00;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053064 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
65 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066 if (audio->feedback == NON_TUNNEL_MODE) {
67 /* Configure PCM output block */
68 rc = q6asm_enc_cfg_blk_pcm(audio->ac,
Sidipotu Ashokbe2a8172011-10-20 09:04:35 +053069 0, /*native sampling rate*/
70 (audio->pcm_cfg.channel_count <= 2) ? 0 : 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071 if (rc < 0) {
72 pr_err("pcm output block config failed\n");
73 break;
74 }
75 }
76 /* turn on both sbr and ps */
77 rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
78 if (rc < 0)
79 pr_err("sbr-ps enable failed\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +053080 aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
81 if (aac_config->sbr_ps_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053083 else if (aac_config->sbr_on_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 aac_cfg.aot = AAC_ENC_MODE_AAC_P;
85 else
86 aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
87
Deepa Madiregama0579ea12011-09-16 04:26:39 +053088 switch (aac_config->format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 case AUDIO_AAC_FORMAT_ADTS:
90 aac_cfg.format = 0x00;
91 break;
92 case AUDIO_AAC_FORMAT_LOAS:
93 aac_cfg.format = 0x01;
94 break;
Deepa Madiregama0579ea12011-09-16 04:26:39 +053095 case AUDIO_AAC_FORMAT_ADIF:
96 aac_cfg.format = 0x02;
97 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 default:
99 case AUDIO_AAC_FORMAT_RAW:
100 aac_cfg.format = 0x03;
101 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530102 aac_cfg.ep_config = aac_config->ep_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103 aac_cfg.section_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530104 aac_config->aac_section_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 aac_cfg.scalefactor_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530106 aac_config->aac_scalefactor_data_resilience_flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 aac_cfg.spectral_data_resilience =
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530108 aac_config->aac_spectral_data_resilience_flag;
109 aac_cfg.ch_cfg = aac_config->channel_configuration;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110 aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
111
112 pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
113 __func__, aac_cfg.format,
114 aac_cfg.aot, aac_cfg.ch_cfg,
115 aac_cfg.sample_rate);
116
117 /* Configure Media format block */
118 rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
119 if (rc < 0) {
120 pr_err("cmd media format block failed\n");
121 break;
122 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530123 rc = audio_aio_enable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 audio->eos_rsp = 0;
125 audio->eos_flag = 0;
126 if (!rc) {
127 audio->enabled = 1;
128 } else {
129 audio->enabled = 0;
130 pr_err("Audio Start procedure failed rc=%d\n", rc);
131 break;
132 }
133 pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
134 audio->ac->session,
135 audio->enabled);
136 if (audio->stopped == 1)
137 audio->stopped = 0;
138 break;
139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 case AUDIO_GET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530141 if (copy_to_user((void *)arg, audio->codec_cfg,
142 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 rc = -EFAULT;
144 break;
145 }
146 break;
147 }
148 case AUDIO_SET_AAC_CONFIG: {
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530149 if (copy_from_user(audio->codec_cfg, (void *)arg,
150 sizeof(struct msm_audio_aac_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 rc = -EFAULT;
152 break;
153 }
154 break;
155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 default:
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530157 pr_debug("Calling utils ioctl\n");
158 rc = audio->codec_ioctl(file, cmd, arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 return rc;
161}
162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163
164static int audio_open(struct inode *inode, struct file *file)
165{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530166 struct q6audio_aio *audio = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168
169#ifdef CONFIG_DEBUG_FS
170 /* 4 bytes represents decoder number, 1 byte for terminate string */
171 char name[sizeof "msm_multi_aac_" + 5];
172#endif
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530173 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
175 if (audio == NULL) {
176 pr_err("Could not allocate memory for aac decode driver\n");
177 return -ENOMEM;
178 }
179
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530180 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
181 GFP_KERNEL);
182 if (audio->codec_cfg == NULL) {
183 pr_err("%s: Could not allocate memory for aac\
184 config\n", __func__);
185 kfree(audio);
186 return -ENOMEM;
187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530189 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
190
191 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_aac_cb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 (void *)audio);
193
194 if (!audio->ac) {
195 pr_err("Could not allocate memory for audio client\n");
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530196 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 kfree(audio);
198 return -ENOMEM;
199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200
201 /* open in T/NT mode */
202 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
203 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
204 FORMAT_MPEG4_AAC);
205 if (rc < 0) {
206 pr_err("NT mode Open failed rc=%d\n", rc);
207 rc = -ENODEV;
208 goto fail;
209 }
210 audio->feedback = NON_TUNNEL_MODE;
211 /* open AAC decoder, expected frames is always 1
212 audio->buf_cfg.frames_per_buf = 0x01;*/
213 audio->buf_cfg.meta_info_enable = 0x01;
214 } else if ((file->f_mode & FMODE_WRITE) &&
215 !(file->f_mode & FMODE_READ)) {
216 rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
217 if (rc < 0) {
218 pr_err("T mode Open failed rc=%d\n", rc);
219 rc = -ENODEV;
220 goto fail;
221 }
222 audio->feedback = TUNNEL_MODE;
223 audio->buf_cfg.meta_info_enable = 0x00;
224 } else {
225 pr_err("Not supported mode\n");
226 rc = -EACCES;
227 goto fail;
228 }
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530229 rc = audio_aio_open(audio, file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230
231#ifdef CONFIG_DEBUG_FS
232 snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
233 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
234 NULL, (void *)audio,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530235 &audio_aac_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236
237 if (IS_ERR(audio->dentry))
238 pr_debug("debugfs_create_file failed\n");
239#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
241 __func__, audio->feedback, audio->ac->session);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530242 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243fail:
244 q6asm_audio_client_free(audio->ac);
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530245 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 kfree(audio);
247 return rc;
248}
249
250static const struct file_operations audio_aac_fops = {
251 .owner = THIS_MODULE,
252 .open = audio_open,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530253 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530255 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256};
257
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530258struct miscdevice audio_multiaac_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 .minor = MISC_DYNAMIC_MINOR,
260 .name = "msm_multi_aac",
261 .fops = &audio_aac_fops,
262};
263
264static int __init audio_aac_init(void)
265{
Deepa Madiregama0579ea12011-09-16 04:26:39 +0530266 return misc_register(&audio_multiaac_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267}
268
269device_initcall(audio_aac_init);