1 /* amr-wbplus audio output device
3 * Copyright (C) 2008 Google, Inc.
4 * Copyright (C) 2008 HTC Corporation
5 * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
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.
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.
17 #include <linux/msm_audio_amrwbplus.h>
18 #include <linux/compat.h>
19 #include "audio_utils_aio.h"
21 static struct miscdevice audio_amrwbplus_misc;
22 static struct ws_mgr audio_amrwbplus_ws_mgr;
24 #ifdef CONFIG_DEBUG_FS
25 static const struct file_operations audio_amrwbplus_debug_fops = {
26 .read = audio_aio_debug_read,
27 .open = audio_aio_debug_open,
29 static void config_debug_fs(struct q6audio_aio *audio)
32 char name[sizeof("msm_amrwbplus_") + 5];
33 snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
35 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
37 &audio_amrwbplus_debug_fops);
38 if (IS_ERR(audio->dentry))
39 pr_debug("debugfs_create_file failed\n");
43 static void config_debug_fs(struct q6audio_aio *audio)
48 static long audio_ioctl_shared(struct file *file, unsigned int cmd,
51 struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
52 struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
53 struct q6audio_aio *audio = file->private_data;
58 pr_err("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
59 audio, audio->ac->session);
60 if (audio->feedback == NON_TUNNEL_MODE) {
61 /* Configure PCM output block */
62 rc = q6asm_enc_cfg_blk_pcm(audio->ac,
63 audio->pcm_cfg.sample_rate,
64 audio->pcm_cfg.channel_count);
66 pr_err("pcm output block config failed\n");
70 amrwbplus_drv_config =
71 (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
73 q6_amrwbplus_cfg.size_bytes =
74 amrwbplus_drv_config->size_bytes;
75 q6_amrwbplus_cfg.version =
76 amrwbplus_drv_config->version;
77 q6_amrwbplus_cfg.num_channels =
78 amrwbplus_drv_config->num_channels;
79 q6_amrwbplus_cfg.amr_band_mode =
80 amrwbplus_drv_config->amr_band_mode;
81 q6_amrwbplus_cfg.amr_dtx_mode =
82 amrwbplus_drv_config->amr_dtx_mode;
83 q6_amrwbplus_cfg.amr_frame_fmt =
84 amrwbplus_drv_config->amr_frame_fmt;
85 q6_amrwbplus_cfg.amr_lsf_idx =
86 amrwbplus_drv_config->amr_lsf_idx;
88 rc = q6asm_media_format_block_amrwbplus(audio->ac,
91 pr_err("q6asm_media_format_block_amrwb+ failed...\n");
94 rc = audio_aio_enable(audio);
101 pr_err("Audio Start procedure failed rc=%d\n", rc);
104 pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
110 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
117 static long audio_ioctl(struct file *file, unsigned int cmd,
120 struct q6audio_aio *audio = file->private_data;
125 rc = audio_ioctl_shared(file, cmd, (void *)arg);
128 case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
129 if ((audio) && (arg) && (audio->codec_cfg)) {
130 if (copy_to_user((void *)arg, audio->codec_cfg,
131 sizeof(struct msm_audio_amrwbplus_config_v2))) {
133 pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2 failed\n",
138 pr_err("%s: wb+ config v2 invalid parameters\n"
145 case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
146 if ((audio) && (arg) && (audio->codec_cfg)) {
147 if (copy_from_user(audio->codec_cfg, (void *)arg,
148 sizeof(struct msm_audio_amrwbplus_config_v2))) {
150 pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2 failed\n",
155 pr_err("%s: wb+ config invalid parameters\n",
163 pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
164 rc = audio->codec_ioctl(file, cmd, arg);
171 struct msm_audio_amrwbplus_config_v2_32 {
182 AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
183 (AUDIO_MAX_COMMON_IOCTL_NUM+2),
184 struct msm_audio_amrwbplus_config_v2_32),
185 AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
186 (AUDIO_MAX_COMMON_IOCTL_NUM+3),
187 struct msm_audio_amrwbplus_config_v2_32)
190 static long audio_compat_ioctl(struct file *file, unsigned int cmd,
193 struct q6audio_aio *audio = file->private_data;
198 rc = audio_ioctl_shared(file, cmd, (void *)arg);
201 case AUDIO_GET_AMRWBPLUS_CONFIG_V2_32: {
202 if (audio && arg && (audio->codec_cfg)) {
203 struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
204 struct msm_audio_amrwbplus_config_v2_32
207 memset(&amrwbplus_config_32, 0,
208 sizeof(amrwbplus_config_32));
211 (struct msm_audio_amrwbplus_config_v2 *)
213 amrwbplus_config_32.size_bytes =
214 amrwbplus_config->size_bytes;
215 amrwbplus_config_32.version =
216 amrwbplus_config->version;
217 amrwbplus_config_32.num_channels =
218 amrwbplus_config->num_channels;
219 amrwbplus_config_32.amr_band_mode =
220 amrwbplus_config->amr_band_mode;
221 amrwbplus_config_32.amr_dtx_mode =
222 amrwbplus_config->amr_dtx_mode;
223 amrwbplus_config_32.amr_frame_fmt =
224 amrwbplus_config->amr_frame_fmt;
225 amrwbplus_config_32.amr_lsf_idx =
226 amrwbplus_config->amr_lsf_idx;
228 if (copy_to_user((void *)arg, &amrwbplus_config_32,
229 sizeof(amrwbplus_config_32))) {
231 pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 failed\n"
235 pr_err("%s: wb+ Get config v2 invalid parameters\n"
241 case AUDIO_SET_AMRWBPLUS_CONFIG_V2_32: {
242 if ((audio) && (arg) && (audio->codec_cfg)) {
243 struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
244 struct msm_audio_amrwbplus_config_v2_32
247 if (copy_from_user(&amrwbplus_config_32, (void *)arg,
248 sizeof(struct msm_audio_amrwbplus_config_v2_32))) {
250 pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 failed\n"
255 (struct msm_audio_amrwbplus_config_v2 *)
257 amrwbplus_config->size_bytes =
258 amrwbplus_config_32.size_bytes;
259 amrwbplus_config->version =
260 amrwbplus_config_32.version;
261 amrwbplus_config->num_channels =
262 amrwbplus_config_32.num_channels;
263 amrwbplus_config->amr_band_mode =
264 amrwbplus_config_32.amr_band_mode;
265 amrwbplus_config->amr_dtx_mode =
266 amrwbplus_config_32.amr_dtx_mode;
267 amrwbplus_config->amr_frame_fmt =
268 amrwbplus_config_32.amr_frame_fmt;
269 amrwbplus_config->amr_lsf_idx =
270 amrwbplus_config_32.amr_lsf_idx;
272 pr_err("%s: wb+ config invalid parameters\n",
279 pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
280 rc = audio->codec_compat_ioctl(file, cmd, arg);
287 #define audio_compat_ioctl NULL
290 static int audio_open(struct inode *inode, struct file *file)
292 struct q6audio_aio *audio = NULL;
295 audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
298 pr_err("kzalloc failed for amrwb+ decode driver\n");
302 kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
303 if (audio->codec_cfg == NULL) {
304 pr_err("%s:failed kzalloc for amrwb+ config structure",
309 audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
310 audio->miscdevice = &audio_amrwbplus_misc;
311 audio->wakelock_voted = false;
312 audio->audio_ws_mgr = &audio_amrwbplus_ws_mgr;
315 q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
318 pr_err("Could not allocate memory for audio client\n");
319 kfree(audio->codec_cfg);
323 rc = audio_aio_open(audio, file);
325 pr_err("%s: audio_aio_open rc=%d\n",
330 /* open in T/NT mode */
331 if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
332 rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
335 pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
339 audio->feedback = NON_TUNNEL_MODE;
340 audio->buf_cfg.frames_per_buf = 0x01;
341 audio->buf_cfg.meta_info_enable = 0x01;
342 } else if ((file->f_mode & FMODE_WRITE) &&
343 !(file->f_mode & FMODE_READ)) {
344 rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
346 pr_err("wb+ T mode Open failed rc=%d\n", rc);
350 audio->feedback = TUNNEL_MODE;
351 audio->buf_cfg.meta_info_enable = 0x00;
353 pr_err("audio_amrwbplus Not supported mode\n");
358 config_debug_fs(audio);
359 pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
364 q6asm_audio_client_free(audio->ac);
365 kfree(audio->codec_cfg);
370 static const struct file_operations audio_amrwbplus_fops = {
371 .owner = THIS_MODULE,
373 .release = audio_aio_release,
374 .unlocked_ioctl = audio_ioctl,
375 .fsync = audio_aio_fsync,
376 .compat_ioctl = audio_compat_ioctl
379 static struct miscdevice audio_amrwbplus_misc = {
380 .minor = MISC_DYNAMIC_MINOR,
381 .name = "msm_amrwbplus",
382 .fops = &audio_amrwbplus_fops,
385 static int __init audio_amrwbplus_init(void)
387 int ret = misc_register(&audio_amrwbplus_misc);
390 device_init_wakeup(audio_amrwbplus_misc.this_device, true);
391 audio_amrwbplus_ws_mgr.ref_cnt = 0;
392 mutex_init(&audio_amrwbplus_ws_mgr.ws_lock);
397 device_initcall(audio_amrwbplus_init);