blob: 0565685b9e26bdea2b27873e08f0066982dbd5ae [file] [log] [blame]
Xiaoyu Ye6415c8a2019-02-01 17:55:06 -08001/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/miscdevice.h>
17#include <linux/uaccess.h>
18#include <linux/sched.h>
19#include <linux/wait.h>
20#include <linux/dma-mapping.h>
21#include <linux/slab.h>
22#include <linux/atomic.h>
23#include <linux/compat.h>
24#include <asm/ioctls.h>
25#include "audio_utils.h"
26
27/*
28 * Define maximum buffer size. Below values are chosen considering the higher
29 * values used among all native drivers.
30 */
31#define MAX_FRAME_SIZE 1536
32#define MAX_FRAMES 5
33#define META_SIZE (sizeof(struct meta_out_dsp))
34#define MAX_BUFFER_SIZE (1 + ((MAX_FRAME_SIZE + META_SIZE) * MAX_FRAMES))
35
36static int audio_in_pause(struct q6audio_in *audio)
37{
38 int rc;
39
40 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
41 if (rc < 0)
42 pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
43 audio->ac->session, rc);
44
45 return rc;
46}
47
48static int audio_in_flush(struct q6audio_in *audio)
49{
50 int rc;
51
52 pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
53 /* Flush if session running */
54 if (audio->enabled) {
55 /* Implicitly issue a pause to the encoder before flushing */
56 rc = audio_in_pause(audio);
57 if (rc < 0) {
58 pr_err("%s:session id %d: pause cmd failed rc=%d\n",
59 __func__, audio->ac->session, rc);
60 return rc;
61 }
62
63 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
64 if (rc < 0) {
65 pr_err("%s:session id %d: flush cmd failed rc=%d\n",
66 __func__, audio->ac->session, rc);
67 return rc;
68 }
69 /* 2nd arg: 0 -> run immediately
70 * 3rd arg: 0 -> msw_ts,
71 * 4th arg: 0 ->lsw_ts
72 */
73 q6asm_run(audio->ac, 0x00, 0x00, 0x00);
74 pr_debug("Rerun the session\n");
75 }
76 audio->rflush = 1;
77 audio->wflush = 1;
78 memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
79 wake_up(&audio->read_wait);
80 /* get read_lock to ensure no more waiting read thread */
81 mutex_lock(&audio->read_lock);
82 audio->rflush = 0;
83 mutex_unlock(&audio->read_lock);
84 wake_up(&audio->write_wait);
85 /* get write_lock to ensure no more waiting write thread */
86 mutex_lock(&audio->write_lock);
87 audio->wflush = 0;
88 mutex_unlock(&audio->write_lock);
89 pr_debug("%s:session id %d: in_bytes %d\n", __func__,
90 audio->ac->session, atomic_read(&audio->in_bytes));
91 pr_debug("%s:session id %d: in_samples %d\n", __func__,
92 audio->ac->session, atomic_read(&audio->in_samples));
93 atomic_set(&audio->in_bytes, 0);
94 atomic_set(&audio->in_samples, 0);
95 atomic_set(&audio->out_count, 0);
96 return 0;
97}
98
99/* must be called with audio->lock held */
100int audio_in_enable(struct q6audio_in *audio)
101{
102 if (audio->enabled)
103 return 0;
104
105 /* 2nd arg: 0 -> run immediately
106 * 3rd arg: 0 -> msw_ts,
107 * 4th arg: 0 ->lsw_ts
108 */
109 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
110}
111
112/* must be called with audio->lock held */
113int audio_in_disable(struct q6audio_in *audio)
114{
115 int rc = 0;
116
117 if (!audio->stopped) {
118 audio->enabled = 0;
119 audio->opened = 0;
120 pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
121 __func__, audio->ac->session,
122 atomic_read(&audio->in_bytes),
123 atomic_read(&audio->in_samples));
124
125 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
126 if (rc < 0)
127 pr_err("%s:session id %d: Failed to close the session rc=%d\n",
128 __func__, audio->ac->session,
129 rc);
130 audio->stopped = 1;
131 memset(audio->out_frame_info, 0,
132 sizeof(audio->out_frame_info));
133 wake_up(&audio->read_wait);
134 wake_up(&audio->write_wait);
135 }
136 pr_debug("%s:session id %d: enabled[%d]\n", __func__,
137 audio->ac->session, audio->enabled);
138 return rc;
139}
140
141int audio_in_buf_alloc(struct q6audio_in *audio)
142{
143 int rc = 0;
144
145 switch (audio->buf_alloc) {
146 case NO_BUF_ALLOC:
147 if (audio->feedback == NON_TUNNEL_MODE) {
148 rc = q6asm_audio_client_buf_alloc(IN,
149 audio->ac,
150 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
151 audio->pcm_cfg.buffer_count);
152 if (rc < 0) {
153 pr_err("%s:session id %d: Buffer Alloc failed\n",
154 __func__,
155 audio->ac->session);
156 rc = -ENOMEM;
157 break;
158 }
159 audio->buf_alloc |= BUF_ALLOC_IN;
160 }
161 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
162 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
163 audio->str_cfg.buffer_count);
164 if (rc < 0) {
165 pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
166 __func__, audio->ac->session, rc);
167 rc = -ENOMEM;
168 break;
169 }
170 audio->buf_alloc |= BUF_ALLOC_OUT;
171 break;
172 case BUF_ALLOC_IN:
173 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
174 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
175 audio->str_cfg.buffer_count);
176 if (rc < 0) {
177 pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
178 __func__, audio->ac->session, rc);
179 rc = -ENOMEM;
180 break;
181 }
182 audio->buf_alloc |= BUF_ALLOC_OUT;
183 break;
184 case BUF_ALLOC_OUT:
185 if (audio->feedback == NON_TUNNEL_MODE) {
186 rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
187 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
188 audio->pcm_cfg.buffer_count);
189 if (rc < 0) {
190 pr_err("%s:session id %d: Buffer Alloc failed\n",
191 __func__,
192 audio->ac->session);
193 rc = -ENOMEM;
194 break;
195 }
196 audio->buf_alloc |= BUF_ALLOC_IN;
197 }
198 break;
199 default:
200 pr_debug("%s:session id %d: buf[%d]\n", __func__,
201 audio->ac->session, audio->buf_alloc);
202 }
203
204 return rc;
205}
206
207int audio_in_set_config(struct file *file,
208 struct msm_audio_config *cfg)
209{
210 int rc = 0;
211 struct q6audio_in *audio = file->private_data;
212
213 if (audio->feedback != NON_TUNNEL_MODE) {
214 pr_err("%s:session id %d: Not sufficient permission to change the record mode\n",
215 __func__, audio->ac->session);
216 rc = -EACCES;
217 goto ret;
218 }
219 if ((cfg->buffer_count > PCM_BUF_COUNT) ||
220 (cfg->buffer_count == 1))
221 cfg->buffer_count = PCM_BUF_COUNT;
222
223 audio->pcm_cfg.buffer_count = cfg->buffer_count;
224 audio->pcm_cfg.buffer_size = cfg->buffer_size;
225 audio->pcm_cfg.channel_count = cfg->channel_count;
226 audio->pcm_cfg.sample_rate = cfg->sample_rate;
227 if (audio->opened && audio->feedback == NON_TUNNEL_MODE) {
228 rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
229 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
230 audio->pcm_cfg.buffer_count);
231 if (rc < 0) {
232 pr_err("%s:session id %d: Buffer Alloc failed\n",
233 __func__, audio->ac->session);
234 rc = -ENOMEM;
235 goto ret;
236 }
237 }
238 audio->buf_alloc |= BUF_ALLOC_IN;
239 rc = 0;
240 pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
241 audio->ac->session, audio->pcm_cfg.buffer_count,
242 audio->pcm_cfg.buffer_size);
243ret:
244 return rc;
245}
246/* ------------------- device --------------------- */
247static long audio_in_ioctl_shared(struct file *file,
248 unsigned int cmd, unsigned long arg)
249{
250 struct q6audio_in *audio = file->private_data;
251 int rc = 0;
252
253 switch (cmd) {
254 case AUDIO_FLUSH: {
255 /* Make sure we're stopped and we wake any threads
256 * that might be blocked holding the read_lock.
257 * While audio->stopped read threads will always
258 * exit immediately.
259 */
260 rc = audio_in_flush(audio);
261 if (rc < 0)
262 pr_err("%s:session id %d: Flush Fail rc=%d\n",
263 __func__, audio->ac->session, rc);
264 else { /* Register back the flushed read buffer with DSP */
265 int cnt = 0;
266
267 while (cnt++ < audio->str_cfg.buffer_count)
268 q6asm_read(audio->ac); /* Push buffer to DSP */
269 pr_debug("register the read buffer\n");
270 }
271 break;
272 }
273 case AUDIO_PAUSE: {
274 pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
275 audio->ac->session);
276 if (audio->enabled)
277 audio_in_pause(audio);
278 break;
279 }
280 case AUDIO_GET_SESSION_ID: {
281 if (copy_to_user((void *) arg, &audio->ac->session,
282 sizeof(u16))) {
283 pr_err("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
284 __func__);
285 rc = -EFAULT;
286 }
287 break;
288 }
289 default:
290 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
291 rc = -EINVAL;
292 }
293 return rc;
294}
295
296long audio_in_ioctl(struct file *file,
297 unsigned int cmd, unsigned long arg)
298{
299 struct q6audio_in *audio = file->private_data;
300 int rc = 0;
301
302 if (cmd == AUDIO_GET_STATS) {
303 struct msm_audio_stats stats;
304
305 memset(&stats, 0, sizeof(stats));
306 stats.byte_count = atomic_read(&audio->in_bytes);
307 stats.sample_count = atomic_read(&audio->in_samples);
308 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
309 return -EFAULT;
310 return rc;
311 }
312
313 mutex_lock(&audio->lock);
314 switch (cmd) {
315 case AUDIO_FLUSH:
316 case AUDIO_PAUSE:
317 case AUDIO_GET_SESSION_ID:
318 rc = audio_in_ioctl_shared(file, cmd, arg);
319 break;
320 case AUDIO_GET_STREAM_CONFIG: {
321 struct msm_audio_stream_config cfg;
322
323 memset(&cfg, 0, sizeof(cfg));
324 cfg.buffer_size = audio->str_cfg.buffer_size;
325 cfg.buffer_count = audio->str_cfg.buffer_count;
326 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
327 rc = -EFAULT;
328 pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
329 __func__, audio->ac->session, cfg.buffer_size,
330 cfg.buffer_count);
331 break;
332 }
333 case AUDIO_SET_STREAM_CONFIG: {
334 struct msm_audio_stream_config cfg;
335
336 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
337 pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG failed\n"
338 , __func__);
339 rc = -EFAULT;
340 break;
341 }
342 /* Minimum single frame size,
343 * but with in maximum frames number
344 */
345 if ((cfg.buffer_size < (audio->min_frame_size +
346 sizeof(struct meta_out_dsp))) ||
347 (cfg.buffer_count < FRAME_NUM)) {
348 rc = -EINVAL;
349 break;
350 }
351 if (cfg.buffer_size > MAX_BUFFER_SIZE) {
352 rc = -EINVAL;
353 break;
354 }
355 audio->str_cfg.buffer_size = cfg.buffer_size;
356 audio->str_cfg.buffer_count = cfg.buffer_count;
357 if (audio->opened) {
358 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
359 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
360 audio->str_cfg.buffer_count);
361 if (rc < 0) {
362 pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
363 __func__, audio->ac->session, rc);
364 rc = -ENOMEM;
365 break;
366 }
367 }
368 audio->buf_alloc |= BUF_ALLOC_OUT;
369 rc = 0;
370 pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
371 __func__, audio->ac->session,
372 audio->str_cfg.buffer_size,
373 audio->str_cfg.buffer_count);
374 break;
375 }
376 case AUDIO_SET_BUF_CFG: {
377 struct msm_audio_buf_cfg cfg;
378
379 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
380 rc = -EFAULT;
381 break;
382 }
383 if ((audio->feedback == NON_TUNNEL_MODE) &&
384 !cfg.meta_info_enable) {
385 rc = -EFAULT;
386 break;
387 }
388
389 /* Restrict the num of frames per buf to coincide with
390 * default buf size
391 */
392 if (cfg.frames_per_buf > audio->max_frames_per_buf) {
393 rc = -EFAULT;
394 break;
395 }
396 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
397 audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
398 pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
399 __func__,
400 audio->ac->session, cfg.meta_info_enable,
401 cfg.frames_per_buf);
402 break;
403 }
404 case AUDIO_GET_BUF_CFG: {
405 pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
406 __func__,
407 audio->ac->session, audio->buf_cfg.meta_info_enable,
408 audio->buf_cfg.frames_per_buf);
409
410 if (copy_to_user((void *)arg, &audio->buf_cfg,
411 sizeof(struct msm_audio_buf_cfg)))
412 rc = -EFAULT;
413 break;
414 }
415 case AUDIO_GET_CONFIG: {
416 if (copy_to_user((void *)arg, &audio->pcm_cfg,
417 sizeof(struct msm_audio_config)))
418 rc = -EFAULT;
419 break;
420
421 }
422 case AUDIO_SET_CONFIG: {
423 struct msm_audio_config cfg;
424
425 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
426 pr_err("%s: copy_from_user for AUDIO_SET_CONFIG failed\n",
427 __func__);
428 rc = -EFAULT;
429 break;
430 }
431 rc = audio_in_set_config(file, &cfg);
432 break;
433 }
434 default:
435 /* call codec specific ioctl */
436 rc = audio->enc_ioctl(file, cmd, arg);
437 }
438 mutex_unlock(&audio->lock);
439 return rc;
440}
441
442#ifdef CONFIG_COMPAT
443struct msm_audio_stats32 {
444 u32 byte_count;
445 u32 sample_count;
446 u32 unused[2];
447};
448
449struct msm_audio_stream_config32 {
450 u32 buffer_size;
451 u32 buffer_count;
452};
453
454struct msm_audio_config32 {
455 u32 buffer_size;
456 u32 buffer_count;
457 u32 channel_count;
458 u32 sample_rate;
459 u32 type;
460 u32 meta_field;
461 u32 bits;
462 u32 unused[3];
463};
464
465struct msm_audio_buf_cfg32 {
466 u32 meta_info_enable;
467 u32 frames_per_buf;
468};
469
470enum {
471 AUDIO_GET_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 3,
472 struct msm_audio_config32),
473 AUDIO_SET_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 4,
474 struct msm_audio_config32),
475 AUDIO_GET_STATS_32 = _IOR(AUDIO_IOCTL_MAGIC, 5,
476 struct msm_audio_stats32),
477 AUDIO_SET_STREAM_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, 80,
478 struct msm_audio_stream_config32),
479 AUDIO_GET_STREAM_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, 81,
480 struct msm_audio_stream_config32),
481 AUDIO_SET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 94,
482 struct msm_audio_buf_cfg32),
483 AUDIO_GET_BUF_CFG_32 = _IOW(AUDIO_IOCTL_MAGIC, 93,
484 struct msm_audio_buf_cfg32),
485};
486
487long audio_in_compat_ioctl(struct file *file,
488 unsigned int cmd, unsigned long arg)
489{
490 struct q6audio_in *audio = file->private_data;
491 int rc = 0;
492
493 if (cmd == AUDIO_GET_STATS_32) {
494 struct msm_audio_stats32 stats_32;
495
496 memset(&stats_32, 0, sizeof(stats_32));
497 stats_32.byte_count = atomic_read(&audio->in_bytes);
498 stats_32.sample_count = atomic_read(&audio->in_samples);
499 if (copy_to_user((void *) arg, &stats_32, sizeof(stats_32))) {
500 pr_err("%s: copy_to_user failed for AUDIO_GET_STATS_32\n",
501 __func__);
502 return -EFAULT;
503 }
504 return rc;
505 }
506
507 mutex_lock(&audio->lock);
508 switch (cmd) {
509 case AUDIO_FLUSH:
510 case AUDIO_PAUSE:
511 case AUDIO_GET_SESSION_ID:
512 rc = audio_in_ioctl_shared(file, cmd, arg);
513 break;
514 case AUDIO_GET_STREAM_CONFIG_32: {
515 struct msm_audio_stream_config32 cfg_32;
516
517 memset(&cfg_32, 0, sizeof(cfg_32));
518 cfg_32.buffer_size = audio->str_cfg.buffer_size;
519 cfg_32.buffer_count = audio->str_cfg.buffer_count;
520 if (copy_to_user((void *)arg, &cfg_32, sizeof(cfg_32))) {
521 pr_err("%s: Copy to user failed\n", __func__);
522 rc = -EFAULT;
523 }
524 pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
525 __func__, audio->ac->session,
526 cfg_32.buffer_size,
527 cfg_32.buffer_count);
528 break;
529 }
530 case AUDIO_SET_STREAM_CONFIG_32: {
531 struct msm_audio_stream_config32 cfg_32;
532 struct msm_audio_stream_config cfg;
533
534 if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
535 pr_err("%s: copy_from_user for AUDIO_SET_STREAM_CONFIG_32 failed\n",
536 __func__);
537 rc = -EFAULT;
538 break;
539 }
540 cfg.buffer_size = cfg_32.buffer_size;
541 cfg.buffer_count = cfg_32.buffer_count;
542 /* Minimum single frame size,
543 * but with in maximum frames number
544 */
545 if ((cfg.buffer_size < (audio->min_frame_size +
546 sizeof(struct meta_out_dsp))) ||
547 (cfg.buffer_count < FRAME_NUM)) {
548 rc = -EINVAL;
549 break;
550 }
551 audio->str_cfg.buffer_size = cfg.buffer_size;
552 audio->str_cfg.buffer_count = cfg.buffer_count;
553 if (audio->opened) {
554 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
555 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
556 audio->str_cfg.buffer_count);
557 if (rc < 0) {
558 pr_err("%s: session id %d:\n",
559 __func__, audio->ac->session);
560 pr_err("Buffer Alloc failed rc=%d\n", rc);
561 rc = -ENOMEM;
562 break;
563 }
564 }
565 audio->buf_alloc |= BUF_ALLOC_OUT;
566 pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
567 __func__, audio->ac->session,
568 audio->str_cfg.buffer_size,
569 audio->str_cfg.buffer_count);
570 break;
571 }
572 case AUDIO_SET_BUF_CFG_32: {
573 struct msm_audio_buf_cfg32 cfg_32;
574 struct msm_audio_buf_cfg cfg;
575
576 if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
577 pr_err("%s: copy_from_user for AUDIO_SET_BUG_CFG_32 failed",
578 __func__);
579 rc = -EFAULT;
580 break;
581 }
582 cfg.meta_info_enable = cfg_32.meta_info_enable;
583 cfg.frames_per_buf = cfg_32.frames_per_buf;
584
585 if ((audio->feedback == NON_TUNNEL_MODE) &&
586 !cfg.meta_info_enable) {
587 rc = -EFAULT;
588 break;
589 }
590
591 /* Restrict the num of frames per buf to coincide with
592 * default buf size
593 */
594 if (cfg.frames_per_buf > audio->max_frames_per_buf) {
595 rc = -EFAULT;
596 break;
597 }
598 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
599 audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
600 pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
601 __func__, audio->ac->session, cfg.meta_info_enable,
602 cfg.frames_per_buf);
603 break;
604 }
605 case AUDIO_GET_BUF_CFG_32: {
606 struct msm_audio_buf_cfg32 cfg_32;
607
608 pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
609 __func__,
610 audio->ac->session, audio->buf_cfg.meta_info_enable,
611 audio->buf_cfg.frames_per_buf);
612 cfg_32.meta_info_enable = audio->buf_cfg.meta_info_enable;
613 cfg_32.frames_per_buf = audio->buf_cfg.frames_per_buf;
614
615 if (copy_to_user((void *)arg, &cfg_32,
616 sizeof(struct msm_audio_buf_cfg32))) {
617 pr_err("%s: Copy to user failed\n", __func__);
618 rc = -EFAULT;
619 }
620 break;
621 }
622 case AUDIO_GET_CONFIG_32: {
623 struct msm_audio_config32 cfg_32;
624
625 memset(&cfg_32, 0, sizeof(cfg_32));
626 cfg_32.buffer_size = audio->pcm_cfg.buffer_size;
627 cfg_32.buffer_count = audio->pcm_cfg.buffer_count;
628 cfg_32.channel_count = audio->pcm_cfg.channel_count;
629 cfg_32.sample_rate = audio->pcm_cfg.sample_rate;
630 cfg_32.type = audio->pcm_cfg.type;
631 cfg_32.meta_field = audio->pcm_cfg.meta_field;
632 cfg_32.bits = audio->pcm_cfg.bits;
633
634 if (copy_to_user((void *)arg, &cfg_32,
635 sizeof(struct msm_audio_config32))) {
636 pr_err("%s: Copy to user failed\n", __func__);
637 rc = -EFAULT;
638 }
639 break;
640 }
641 case AUDIO_SET_CONFIG_32: {
642 struct msm_audio_config32 cfg_32;
643 struct msm_audio_config cfg;
644
645 if (copy_from_user(&cfg_32, (void *)arg, sizeof(cfg_32))) {
646 pr_err("%s: copy_from_user for AUDIO_SET_CONFIG_32 failed\n",
647 __func__);
648 rc = -EFAULT;
649 break;
650 }
651 cfg.buffer_size = cfg_32.buffer_size;
652 cfg.buffer_count = cfg_32.buffer_count;
653 cfg.channel_count = cfg_32.channel_count;
654 cfg.sample_rate = cfg_32.sample_rate;
655 cfg.type = cfg_32.type;
656 cfg.meta_field = cfg_32.meta_field;
657 cfg.bits = cfg_32.bits;
658 rc = audio_in_set_config(file, &cfg);
659 break;
660 }
661 default:
662 /* call codec specific ioctl */
663 rc = audio->enc_compat_ioctl(file, cmd, arg);
664 }
665 mutex_unlock(&audio->lock);
666 return rc;
667}
668#endif
669
670ssize_t audio_in_read(struct file *file,
671 char __user *buf,
672 size_t count, loff_t *pos)
673{
674 struct q6audio_in *audio = file->private_data;
675 const char __user *start = buf;
676 unsigned char *data;
677 uint32_t offset = 0;
678 uint32_t size = 0;
679 int rc = 0;
680 uint32_t idx;
681 struct meta_out_dsp meta;
682 uint32_t bytes_to_copy = 0;
683 uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
684 (sizeof(unsigned char) +
685 (sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
686
687 memset(&meta, 0, sizeof(meta));
688 pr_debug("%s:session id %d: read - %zd\n", __func__, audio->ac->session,
689 count);
690 if (audio->reset_event)
691 return -ENETRESET;
692
693 if (!audio->enabled)
694 return -EFAULT;
695 mutex_lock(&audio->read_lock);
696 while (count > 0) {
697 rc = wait_event_interruptible(
698 audio->read_wait,
699 ((atomic_read(&audio->out_count) > 0) ||
700 (audio->stopped) ||
701 audio->rflush || audio->eos_rsp ||
702 audio->event_abort));
703
704 if (audio->event_abort) {
705 rc = -EIO;
706 break;
707 }
708
709
710 if (rc < 0)
711 break;
712
713 if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
714 audio->rflush) {
715 pr_debug("%s:session id %d: driver in stop state or flush,No more buf to read",
716 __func__,
717 audio->ac->session);
718 rc = 0;/* End of File */
719 break;
720 }
721 if (!(atomic_read(&audio->out_count)) &&
722 (audio->eos_rsp == 1) &&
723 (count >= (sizeof(unsigned char) +
724 sizeof(struct meta_out_dsp)))) {
725 unsigned char num_of_frames;
726
727 pr_info("%s:session id %d: eos %d at output\n",
728 __func__, audio->ac->session, audio->eos_rsp);
729 if (buf != start)
730 break;
731 num_of_frames = 0xFF;
732 if (copy_to_user(buf, &num_of_frames,
733 sizeof(unsigned char))) {
734 rc = -EFAULT;
735 break;
736 }
737 buf += sizeof(unsigned char);
738 meta.frame_size = 0xFFFF;
739 meta.encoded_pcm_samples = 0xFFFF;
740 meta.msw_ts = 0x00;
741 meta.lsw_ts = 0x00;
742 meta.nflags = AUD_EOS_SET;
743 audio->eos_rsp = 0;
744 if (copy_to_user(buf, &meta, sizeof(meta))) {
745 rc = -EFAULT;
746 break;
747 }
748 buf += sizeof(meta);
749 break;
750 }
751 data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
752 &size, &idx);
753 if ((count >= (size + mfield_size)) && data) {
754 if (audio->buf_cfg.meta_info_enable) {
755 if (copy_to_user(buf,
756 &audio->out_frame_info[idx][0],
757 sizeof(unsigned char))) {
758 rc = -EFAULT;
759 break;
760 }
761 bytes_to_copy =
762 (size + audio->out_frame_info[idx][1]);
Weiyin Jiang1cc531e2018-10-22 16:40:10 +0800763 if (bytes_to_copy == 0) {
764 rc = 0;
765 break;
766 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530767 /* Number of frames information copied */
768 buf += sizeof(unsigned char);
769 count -= sizeof(unsigned char);
770 } else {
771 offset = audio->out_frame_info[idx][1];
772 bytes_to_copy = size;
773 }
774
775 pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
776 __func__, audio->ac->session,
777 audio->out_frame_info[idx][1],
778 audio->out_frame_info[idx][0]);
779
780 if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
781 rc = -EFAULT;
782 break;
783 }
784 count -= bytes_to_copy;
785 buf += bytes_to_copy;
786 } else {
787 pr_err("%s:session id %d: short read data[%pK] bytesavail[%d]bytesrequest[%zd]\n",
788 __func__,
789 audio->ac->session,
790 data, size, count);
791 }
792 atomic_dec(&audio->out_count);
793 q6asm_read(audio->ac);
794 break;
795 }
796 mutex_unlock(&audio->read_lock);
797
798 pr_debug("%s:session id %d: read: %zd bytes\n", __func__,
799 audio->ac->session, (buf-start));
Weiyin Jiang1cc531e2018-10-22 16:40:10 +0800800 if (!rc) {
801 if (buf > start)
802 return buf - start;
803 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530804 return rc;
805}
806
807static int extract_meta_info(char *buf, unsigned long *msw_ts,
808 unsigned long *lsw_ts, unsigned int *flags)
809{
810 struct meta_in *meta = (struct meta_in *)buf;
811 *msw_ts = meta->ntimestamp.highpart;
812 *lsw_ts = meta->ntimestamp.lowpart;
813 *flags = meta->nflags;
814 return 0;
815}
816
817ssize_t audio_in_write(struct file *file,
818 const char __user *buf,
819 size_t count, loff_t *pos)
820{
821 struct q6audio_in *audio = file->private_data;
822 const char __user *start = buf;
823 size_t xfer = 0;
824 char *cpy_ptr;
825 int rc = 0;
826 unsigned char *data;
827 uint32_t size = 0;
828 uint32_t idx = 0;
829 uint32_t nflags = 0;
830 unsigned long msw_ts = 0;
831 unsigned long lsw_ts = 0;
832 uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
833 sizeof(struct meta_in);
834
835 pr_debug("%s:session id %d: to write[%zd]\n", __func__,
836 audio->ac->session, count);
837 if (audio->reset_event)
838 return -ENETRESET;
839
840 if (!audio->enabled)
841 return -EFAULT;
842 mutex_lock(&audio->write_lock);
843
844 while (count > 0) {
845 rc = wait_event_interruptible(audio->write_wait,
846 ((atomic_read(&audio->in_count) > 0) ||
847 (audio->stopped) ||
848 (audio->wflush) || (audio->event_abort)));
849
850 if (audio->event_abort) {
851 rc = -EIO;
852 break;
853 }
854
855 if (rc < 0)
856 break;
857 if (audio->stopped || audio->wflush) {
858 pr_debug("%s: session id %d: stop or flush\n", __func__,
859 audio->ac->session);
860 rc = -EBUSY;
861 break;
862 }
863 /* if no PCM data, might have only eos buffer
864 * such case do not hold cpu buffer
865 */
866 if ((buf == start) && (count == mfield_size)) {
867 char eos_buf[sizeof(struct meta_in)];
868 /* Processing beginning of user buffer */
869 if (copy_from_user(eos_buf, buf, mfield_size)) {
870 rc = -EFAULT;
871 break;
872 }
873 /* Check if EOS flag is set and buffer has
874 * contains just meta field
875 */
876 extract_meta_info(eos_buf, &msw_ts, &lsw_ts,
877 &nflags);
878 buf += mfield_size;
879 /* send the EOS and return */
880 pr_debug("%s:session id %d: send EOS 0x%8x\n",
881 __func__,
882 audio->ac->session, nflags);
883 break;
884 }
885 data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
886 &size, &idx);
887 if (!data) {
888 pr_debug("%s:session id %d: No buf available\n",
889 __func__, audio->ac->session);
890 continue;
891 }
892 cpy_ptr = data;
893 if (audio->buf_cfg.meta_info_enable) {
894 if (buf == start) {
895 /* Processing beginning of user buffer */
896 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
897 rc = -EFAULT;
898 break;
899 }
900 /* Check if EOS flag is set and buffer has
901 * contains just meta field
902 */
903 extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
904 &nflags);
905 buf += mfield_size;
906 count -= mfield_size;
907 } else {
908 pr_debug("%s:session id %d: continuous buffer\n",
909 __func__, audio->ac->session);
910 }
911 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530912
Xiaoyu Ye6415c8a2019-02-01 17:55:06 -0800913 xfer = (count > size) ? size : count;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530914 if (copy_from_user(cpy_ptr, buf, xfer)) {
915 rc = -EFAULT;
916 break;
917 }
918 rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
919 if (rc < 0) {
920 rc = -EFAULT;
921 break;
922 }
923 atomic_dec(&audio->in_count);
924 count -= xfer;
925 buf += xfer;
926 }
927 mutex_unlock(&audio->write_lock);
928 pr_debug("%s:session id %d: eos_condition 0x%x buf[0x%pK] start[0x%pK]\n",
929 __func__, audio->ac->session,
930 nflags, buf, start);
931 if (nflags & AUD_EOS_SET) {
932 rc = q6asm_cmd(audio->ac, CMD_EOS);
933 pr_info("%s:session id %d: eos %d at input\n", __func__,
934 audio->ac->session, audio->eos_rsp);
935 }
936 pr_debug("%s:session id %d: Written %zd Avail Buf[%d]", __func__,
937 audio->ac->session, (buf - start - mfield_size),
938 atomic_read(&audio->in_count));
939 if (!rc) {
940 if (buf > start)
941 return buf - start;
942 }
943 return rc;
944}
945
946int audio_in_release(struct inode *inode, struct file *file)
947{
948 struct q6audio_in *audio = file->private_data;
949
950 pr_info("%s: session id %d\n", __func__, audio->ac->session);
951 mutex_lock(&audio->lock);
952 audio_in_disable(audio);
953 q6asm_audio_client_free(audio->ac);
954 mutex_unlock(&audio->lock);
955 kfree(audio->enc_cfg);
956 kfree(audio->codec_cfg);
957 kfree(audio);
958 return 0;
959}