blob: ce49cac47fa58f3bceafada377a1081fece710e8 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* wmapro audio output device
2 *
3 * Copyright (C) 2008 Google, Inc.
4 * Copyright (C) 2008 HTC Corporation
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08005 * Copyright (c) 2009-2013, 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
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053018#include <linux/types.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019#include <linux/msm_audio_wmapro.h>
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053020#include "audio_utils_aio.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#ifdef CONFIG_DEBUG_FS
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053023static const struct file_operations audio_wmapro_debug_fops = {
24 .read = audio_aio_debug_read,
25 .open = audio_aio_debug_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026};
27#endif
28
29static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
30{
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053031 struct q6audio_aio *audio = file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032 int rc = 0;
33
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034 switch (cmd) {
35 case AUDIO_START: {
36 struct asm_wmapro_cfg wmapro_cfg;
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053037 struct msm_audio_wmapro_config *wmapro_config;
38 pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
39 audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 if (audio->feedback == NON_TUNNEL_MODE) {
41 /* Configure PCM output block */
42 rc = q6asm_enc_cfg_blk_pcm(audio->ac,
43 audio->pcm_cfg.sample_rate,
44 audio->pcm_cfg.channel_count);
45 if (rc < 0) {
46 pr_err("pcm output block config failed\n");
47 break;
48 }
49 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053050 wmapro_config = (struct msm_audio_wmapro_config *)
51 audio->codec_cfg;
52 if ((wmapro_config->formattag == 0x162) ||
53 (wmapro_config->formattag == 0x163) ||
54 (wmapro_config->formattag == 0x166) ||
55 (wmapro_config->formattag == 0x167)) {
56 wmapro_cfg.format_tag = wmapro_config->formattag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057 } else {
58 pr_err("%s:AUDIO_START failed: formattag = %d\n",
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053059 __func__, wmapro_config->formattag);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060 rc = -EINVAL;
61 break;
62 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053063 if ((wmapro_config->numchannels == 1) ||
64 (wmapro_config->numchannels == 2)) {
65 wmapro_cfg.ch_cfg = wmapro_config->numchannels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066 } else {
67 pr_err("%s:AUDIO_START failed: channels = %d\n",
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053068 __func__, wmapro_config->numchannels);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069 rc = -EINVAL;
70 break;
71 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053072 if ((wmapro_config->samplingrate <= 48000) ||
73 (wmapro_config->samplingrate > 0)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074 wmapro_cfg.sample_rate =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053075 wmapro_config->samplingrate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076 } else {
77 pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053078 __func__, wmapro_config->samplingrate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079 rc = -EINVAL;
80 break;
81 }
82 wmapro_cfg.avg_bytes_per_sec =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053083 wmapro_config->avgbytespersecond;
84 if ((wmapro_config->asfpacketlength <= 13376) ||
85 (wmapro_config->asfpacketlength > 0)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 wmapro_cfg.block_align =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053087 wmapro_config->asfpacketlength;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 } else {
89 pr_err("%s:AUDIO_START failed: block_align = %d\n",
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053090 __func__, wmapro_config->asfpacketlength);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 rc = -EINVAL;
92 break;
93 }
Tejas Shikhare3e2a6102011-11-03 15:14:13 -070094 if ((wmapro_config->validbitspersample == 16) ||
95 (wmapro_config->validbitspersample == 24)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 wmapro_cfg.valid_bits_per_sample =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +053097 wmapro_config->validbitspersample;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 } else {
99 pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
100 __func__,
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530101 wmapro_config->validbitspersample);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 rc = -EINVAL;
103 break;
104 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530105 if ((wmapro_config->channelmask == 4) ||
106 (wmapro_config->channelmask == 3)) {
107 wmapro_cfg.ch_mask = wmapro_config->channelmask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 } else {
109 pr_err("%s:AUDIO_START failed: channel_mask = %d\n",
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530110 __func__, wmapro_config->channelmask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 rc = -EINVAL;
112 break;
113 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530114 wmapro_cfg.encode_opt = wmapro_config->encodeopt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115 wmapro_cfg.adv_encode_opt =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530116 wmapro_config->advancedencodeopt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117 wmapro_cfg.adv_encode_opt2 =
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530118 wmapro_config->advancedencodeopt2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 /* Configure Media format block */
120 rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg);
121 if (rc < 0) {
122 pr_err("cmd media format block failed\n");
123 break;
124 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +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_debug("AUDIO_START success enable[%d]\n", 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_WMAPRO_CONFIG: {
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530141 if (copy_to_user((void *)arg, audio->codec_cfg,
142 sizeof(struct msm_audio_wmapro_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 rc = -EFAULT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 }
145 break;
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 case AUDIO_SET_WMAPRO_CONFIG: {
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530148 if (copy_from_user(audio->codec_cfg, (void *)arg,
149 sizeof(struct msm_audio_wmapro_config))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 rc = -EFAULT;
151 break;
152 }
153 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 default:
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530156 pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
157 rc = audio->codec_ioctl(file, cmd, arg);
158 if (rc)
159 pr_err("Failed in utils_ioctl: %d\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 return rc;
162}
163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164static int audio_open(struct inode *inode, struct file *file)
165{
Deepa Madiregama3bd756d2011-08-12 03:43:34 +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_wmapro_" + 5];
172#endif
Deepa Madiregama3bd756d2011-08-12 03:43:34 +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 wma decode driver\n");
177 return -ENOMEM;
178 }
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530179 audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
180 GFP_KERNEL);
181 if (audio->codec_cfg == NULL) {
Harmandeep Singhc35fa07d2012-05-31 07:08:59 -0700182 pr_err("%s: Could not allocate memory for wmapro"
183 "config\n", __func__);
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530184 kfree(audio);
185 return -ENOMEM;
186 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
Harmandeep Singhc35fa07d2012-05-31 07:08:59 -0700191 audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_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 Madiregama3bd756d2011-08-12 03:43:34 +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_WMA_V10PRO);
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 WMA 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_WMA_V10PRO);
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 Madiregama3bd756d2011-08-12 03:43:34 +0530229 rc = audio_aio_open(audio, file);
Kuirong Wang86d5e7a2013-02-12 18:45:49 -0800230 if (rc < 0) {
231 pr_err("audio_aio_open rc=%d\n", rc);
232 goto fail;
233 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234
235#ifdef CONFIG_DEBUG_FS
236 snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
237 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
238 NULL, (void *)audio,
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530239 &audio_wmapro_debug_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240
241 if (IS_ERR(audio->dentry))
242 pr_debug("debugfs_create_file failed\n");
243#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
245 audio->ac->session);
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530246 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247fail:
248 q6asm_audio_client_free(audio->ac);
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530249 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 kfree(audio);
251 return rc;
252}
253
254static const struct file_operations audio_wmapro_fops = {
255 .owner = THIS_MODULE,
256 .open = audio_open,
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530257 .release = audio_aio_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 .unlocked_ioctl = audio_ioctl,
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530259 .fsync = audio_aio_fsync,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260};
261
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530262struct miscdevice audio_wmapro_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 .minor = MISC_DYNAMIC_MINOR,
264 .name = "msm_wmapro",
265 .fops = &audio_wmapro_fops,
266};
267
268static int __init audio_wmapro_init(void)
269{
Deepa Madiregama3bd756d2011-08-12 03:43:34 +0530270 return misc_register(&audio_wmapro_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271}
272
273device_initcall(audio_wmapro_init);