OSDN Git Service

treewide: Fix code issues detected using GCC 8
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / misc / qcom / qdsp6v2 / audio_amrwbplus.c
1 /* amr-wbplus audio output device
2  *
3  * Copyright (C) 2008 Google, Inc.
4  * Copyright (C) 2008 HTC Corporation
5  * Copyright (c) 2010-2016, The Linux Foundation. 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 #include <linux/msm_audio_amrwbplus.h>
18 #include <linux/compat.h>
19 #include "audio_utils_aio.h"
20
21 static struct miscdevice audio_amrwbplus_misc;
22 static struct ws_mgr audio_amrwbplus_ws_mgr;
23
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,
28 };
29 static void config_debug_fs(struct q6audio_aio *audio)
30 {
31         if (audio != NULL) {
32                 char name[sizeof("msm_amrwbplus_") + 5];
33                 snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
34                         audio->ac->session);
35                 audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
36                                                 NULL, (void *)audio,
37                                                 &audio_amrwbplus_debug_fops);
38                 if (IS_ERR(audio->dentry))
39                         pr_debug("debugfs_create_file failed\n");
40         }
41 }
42 #else
43 static void config_debug_fs(struct q6audio_aio *audio)
44 {
45 }
46 #endif
47
48 static long audio_ioctl_shared(struct file *file, unsigned int cmd,
49                                         void *arg)
50 {
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;
54         int rc = 0;
55
56         switch (cmd) {
57         case AUDIO_START:
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);
65                         if (rc < 0) {
66                                 pr_err("pcm output block config failed\n");
67                                 break;
68                         }
69                 }
70                 amrwbplus_drv_config =
71                 (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
72
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;
87
88                 rc = q6asm_media_format_block_amrwbplus(audio->ac,
89                                                         &q6_amrwbplus_cfg);
90                 if (rc < 0) {
91                         pr_err("q6asm_media_format_block_amrwb+ failed...\n");
92                         break;
93                 }
94                 rc = audio_aio_enable(audio);
95                 audio->eos_rsp = 0;
96                 audio->eos_flag = 0;
97                 if (!rc) {
98                         audio->enabled = 1;
99                 } else {
100                         audio->enabled = 0;
101                         pr_err("Audio Start procedure failed rc=%d\n", rc);
102                         break;
103                 }
104                 pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
105                         audio->ac->session,
106                         audio->enabled);
107                 audio->stopped = 0;
108                 break;
109         default:
110                 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
111                 rc = -EINVAL;
112                 break;
113         }
114         return rc;
115 }
116
117 static long audio_ioctl(struct file *file, unsigned int cmd,
118                                                 unsigned long arg)
119 {
120         struct q6audio_aio *audio = file->private_data;
121         int rc = 0;
122
123         switch (cmd) {
124         case AUDIO_START: {
125                 rc = audio_ioctl_shared(file, cmd, (void *)arg);
126                 break;
127         }
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))) {
132                                 rc = -EFAULT;
133                                 pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2 failed\n",
134                                         __func__);
135                                 break;
136                         }
137                         } else {
138                                 pr_err("%s: wb+ config v2 invalid parameters\n"
139                                         , __func__);
140                                 rc = -EFAULT;
141                                 break;
142                         }
143                 break;
144         }
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))) {
149                                 rc = -EFAULT;
150                                 pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2 failed\n",
151                                         __func__);
152                                 break;
153                         }
154                         } else {
155                                 pr_err("%s: wb+ config invalid parameters\n",
156                                         __func__);
157                                 rc = -EFAULT;
158                                 break;
159                         }
160                 break;
161         }
162         default: {
163                 pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
164                 rc = audio->codec_ioctl(file, cmd, arg);
165                 break;
166         }
167         }
168         return rc;
169 }
170 #ifdef CONFIG_COMPAT
171 struct msm_audio_amrwbplus_config_v2_32 {
172         u32 size_bytes;
173         u32 version;
174         u32 num_channels;
175         u32 amr_band_mode;
176         u32 amr_dtx_mode;
177         u32 amr_frame_fmt;
178         u32 amr_lsf_idx;
179 };
180
181 enum {
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)
188 };
189
190 static long audio_compat_ioctl(struct file *file, unsigned int cmd,
191                                         unsigned long arg)
192 {
193         struct q6audio_aio *audio = file->private_data;
194         int rc = 0;
195
196         switch (cmd) {
197         case AUDIO_START: {
198                 rc = audio_ioctl_shared(file, cmd, (void *)arg);
199                 break;
200         }
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
205                                                 amrwbplus_config_32;
206
207                         memset(&amrwbplus_config_32, 0,
208                                         sizeof(amrwbplus_config_32));
209
210                         amrwbplus_config =
211                                 (struct msm_audio_amrwbplus_config_v2 *)
212                                 audio->codec_cfg;
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;
227
228                         if (copy_to_user((void *)arg, &amrwbplus_config_32,
229                                 sizeof(amrwbplus_config_32))) {
230                                 rc = -EFAULT;
231                                 pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 failed\n"
232                                         , __func__);
233                         }
234                 } else {
235                         pr_err("%s: wb+ Get config v2 invalid parameters\n"
236                                 , __func__);
237                         rc = -EFAULT;
238                 }
239                 break;
240         }
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
245                                                         amrwbplus_config_32;
246
247                         if (copy_from_user(&amrwbplus_config_32, (void *)arg,
248                         sizeof(struct msm_audio_amrwbplus_config_v2_32))) {
249                                 rc = -EFAULT;
250                                 pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 failed\n"
251                                         , __func__);
252                                 break;
253                         }
254                         amrwbplus_config =
255                          (struct msm_audio_amrwbplus_config_v2 *)
256                                                 audio->codec_cfg;
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;
271                 } else {
272                         pr_err("%s: wb+ config invalid parameters\n",
273                                 __func__);
274                         rc = -EFAULT;
275                 }
276                 break;
277         }
278         default: {
279                 pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
280                 rc = audio->codec_compat_ioctl(file, cmd, arg);
281                 break;
282         }
283         }
284         return rc;
285 }
286 #else
287 #define audio_compat_ioctl NULL
288 #endif
289
290 static int audio_open(struct inode *inode, struct file *file)
291 {
292         struct q6audio_aio *audio = NULL;
293         int rc = 0;
294
295         audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
296
297         if (audio == NULL) {
298                 pr_err("kzalloc failed for amrwb+ decode driver\n");
299                 return -ENOMEM;
300         }
301         audio->codec_cfg =
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",
305                         __func__);
306                 kfree(audio);
307                 return -ENOMEM;
308         }
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;
313
314         audio->ac =
315         q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
316
317         if (!audio->ac) {
318                 pr_err("Could not allocate memory for audio client\n");
319                 kfree(audio->codec_cfg);
320                 kfree(audio);
321                 return -ENOMEM;
322         }
323         rc = audio_aio_open(audio, file);
324         if (rc < 0) {
325                 pr_err("%s: audio_aio_open rc=%d\n",
326                         __func__, rc);
327                 goto fail;
328         }
329
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,
333                                         FORMAT_AMR_WB_PLUS);
334                 if (rc < 0) {
335                         pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
336                         rc = -ENODEV;
337                         goto fail;
338                 }
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);
345                         if (rc < 0) {
346                                 pr_err("wb+ T mode Open failed rc=%d\n", rc);
347                                 rc = -ENODEV;
348                                 goto fail;
349                         }
350                 audio->feedback = TUNNEL_MODE;
351                 audio->buf_cfg.meta_info_enable = 0x00;
352         } else {
353                 pr_err("audio_amrwbplus Not supported mode\n");
354                 rc = -EACCES;
355                 goto fail;
356         }
357
358         config_debug_fs(audio);
359         pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
360                 audio->feedback,
361                 audio->ac->session);
362         return 0;
363 fail:
364         q6asm_audio_client_free(audio->ac);
365         kfree(audio->codec_cfg);
366         kfree(audio);
367         return rc;
368 }
369
370 static const struct file_operations audio_amrwbplus_fops = {
371         .owner = THIS_MODULE,
372         .open = audio_open,
373         .release = audio_aio_release,
374         .unlocked_ioctl = audio_ioctl,
375         .fsync = audio_aio_fsync,
376         .compat_ioctl = audio_compat_ioctl
377 };
378
379 static struct miscdevice audio_amrwbplus_misc = {
380         .minor = MISC_DYNAMIC_MINOR,
381         .name = "msm_amrwbplus",
382         .fops = &audio_amrwbplus_fops,
383 };
384
385 static int __init audio_amrwbplus_init(void)
386 {
387         int ret = misc_register(&audio_amrwbplus_misc);
388
389         if (ret == 0)
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);
393
394         return ret;
395 }
396
397 device_initcall(audio_amrwbplus_init);