blob: ccacd3ec9c885fb539963b1064c8aacd5ae97483 [file] [log] [blame]
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -08001/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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>
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -080022#include <linux/atomic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <asm/ioctls.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include "audio_utils.h"
25
26static int audio_in_pause(struct q6audio_in *audio)
27{
28 int rc;
29
30 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
31 if (rc < 0)
32 pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
33 audio->ac->session, rc);
34
35 return rc;
36}
37
38static int audio_in_flush(struct q6audio_in *audio)
39{
40 int rc;
41
42 pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
Rajesha Kini72a8b612011-08-10 11:19:55 +053043 /* Flush if session running */
44 if (audio->enabled) {
45 /* Implicitly issue a pause to the encoder before flushing */
46 rc = audio_in_pause(audio);
47 if (rc < 0) {
48 pr_err("%s:session id %d: pause cmd failed rc=%d\n",
49 __func__, audio->ac->session, rc);
50 return rc;
51 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052
Rajesha Kini72a8b612011-08-10 11:19:55 +053053 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
54 if (rc < 0) {
55 pr_err("%s:session id %d: flush cmd failed rc=%d\n",
56 __func__, audio->ac->session, rc);
57 return rc;
58 }
59 /* 2nd arg: 0 -> run immediately
60 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
61 q6asm_run(audio->ac, 0x00, 0x00, 0x00);
62 pr_debug("Rerun the session\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063 }
64 audio->rflush = 1;
65 audio->wflush = 1;
66 memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
67 wake_up(&audio->read_wait);
68 /* get read_lock to ensure no more waiting read thread */
69 mutex_lock(&audio->read_lock);
70 audio->rflush = 0;
71 mutex_unlock(&audio->read_lock);
72 wake_up(&audio->write_wait);
73 /* get write_lock to ensure no more waiting write thread */
74 mutex_lock(&audio->write_lock);
75 audio->wflush = 0;
76 mutex_unlock(&audio->write_lock);
77 pr_debug("%s:session id %d: in_bytes %d\n", __func__,
78 audio->ac->session, atomic_read(&audio->in_bytes));
79 pr_debug("%s:session id %d: in_samples %d\n", __func__,
80 audio->ac->session, atomic_read(&audio->in_samples));
81 atomic_set(&audio->in_bytes, 0);
82 atomic_set(&audio->in_samples, 0);
Rajesha Kini72a8b612011-08-10 11:19:55 +053083 atomic_set(&audio->out_count, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 return 0;
85}
86
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087/* must be called with audio->lock held */
88int audio_in_enable(struct q6audio_in *audio)
89{
90 if (audio->enabled)
91 return 0;
92
93 /* 2nd arg: 0 -> run immediately
94 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
95 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
96}
97
98/* must be called with audio->lock held */
99int audio_in_disable(struct q6audio_in *audio)
100{
101 int rc = 0;
quic_mqiu95bf1422013-10-29 09:53:09 +0800102 if (!audio->stopped) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103 audio->enabled = 0;
104 audio->opened = 0;
105 pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
106 __func__, audio->ac->session,
107 atomic_read(&audio->in_bytes),
108 atomic_read(&audio->in_samples));
109
110 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
111 if (rc < 0)
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800112 pr_err("%s:session id %d: Failed to close the session rc=%d\n",
113 __func__, audio->ac->session,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114 rc);
115 audio->stopped = 1;
116 memset(audio->out_frame_info, 0,
117 sizeof(audio->out_frame_info));
118 wake_up(&audio->read_wait);
119 wake_up(&audio->write_wait);
120 }
121 pr_debug("%s:session id %d: enabled[%d]\n", __func__,
122 audio->ac->session, audio->enabled);
123 return rc;
124}
125
126int audio_in_buf_alloc(struct q6audio_in *audio)
127{
128 int rc = 0;
129
130 switch (audio->buf_alloc) {
131 case NO_BUF_ALLOC:
132 if (audio->feedback == NON_TUNNEL_MODE) {
133 rc = q6asm_audio_client_buf_alloc(IN,
134 audio->ac,
135 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
136 audio->pcm_cfg.buffer_count);
137 if (rc < 0) {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800138 pr_err("%s:session id %d: Buffer Alloc failed\n",
139 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 audio->ac->session);
141 rc = -ENOMEM;
142 break;
143 }
144 audio->buf_alloc |= BUF_ALLOC_IN;
145 }
146 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
147 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
148 audio->str_cfg.buffer_count);
149 if (rc < 0) {
150 pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
151 __func__, audio->ac->session, rc);
152 rc = -ENOMEM;
153 break;
154 }
155 audio->buf_alloc |= BUF_ALLOC_OUT;
156 break;
157 case BUF_ALLOC_IN:
158 rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
159 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
160 audio->str_cfg.buffer_count);
161 if (rc < 0) {
162 pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
163 __func__, audio->ac->session, rc);
164 rc = -ENOMEM;
165 break;
166 }
167 audio->buf_alloc |= BUF_ALLOC_OUT;
168 break;
169 case BUF_ALLOC_OUT:
170 if (audio->feedback == NON_TUNNEL_MODE) {
171 rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
172 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
173 audio->pcm_cfg.buffer_count);
174 if (rc < 0) {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800175 pr_err("%s:session id %d: Buffer Alloc failed\n",
176 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177 audio->ac->session);
178 rc = -ENOMEM;
179 break;
180 }
181 audio->buf_alloc |= BUF_ALLOC_IN;
182 }
183 break;
184 default:
185 pr_debug("%s:session id %d: buf[%d]\n", __func__,
186 audio->ac->session, audio->buf_alloc);
187 }
188
189 return rc;
190}
191/* ------------------- device --------------------- */
192long audio_in_ioctl(struct file *file,
193 unsigned int cmd, unsigned long arg)
194{
195 struct q6audio_in *audio = file->private_data;
196 int rc = 0;
197
198 if (cmd == AUDIO_GET_STATS) {
199 struct msm_audio_stats stats;
Kiran Kandiccf19062013-10-09 11:27:59 -0700200 memset(&stats, 0, sizeof(stats));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 stats.byte_count = atomic_read(&audio->in_bytes);
202 stats.sample_count = atomic_read(&audio->in_samples);
203 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
204 return -EFAULT;
205 return rc;
206 }
207
208 mutex_lock(&audio->lock);
209 switch (cmd) {
210 case AUDIO_FLUSH: {
211 /* Make sure we're stopped and we wake any threads
212 * that might be blocked holding the read_lock.
213 * While audio->stopped read threads will always
214 * exit immediately.
215 */
216 rc = audio_in_flush(audio);
217 if (rc < 0)
218 pr_err("%s:session id %d: Flush Fail rc=%d\n",
219 __func__, audio->ac->session, rc);
Rajesha Kini72a8b612011-08-10 11:19:55 +0530220 else { /* Register back the flushed read buffer with DSP */
221 int cnt = 0;
222 while (cnt++ < audio->str_cfg.buffer_count)
223 q6asm_read(audio->ac); /* Push buffer to DSP */
224 pr_debug("register the read buffer\n");
225 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 break;
227 }
228 case AUDIO_PAUSE: {
229 pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
230 audio->ac->session);
231 if (audio->enabled)
232 audio_in_pause(audio);
233 break;
234 }
235 case AUDIO_GET_STREAM_CONFIG: {
236 struct msm_audio_stream_config cfg;
237 memset(&cfg, 0, sizeof(cfg));
238 cfg.buffer_size = audio->str_cfg.buffer_size;
239 cfg.buffer_count = audio->str_cfg.buffer_count;
240 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
241 rc = -EFAULT;
242 pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
243 __func__, audio->ac->session, cfg.buffer_size,
244 cfg.buffer_count);
245 break;
246 }
247 case AUDIO_SET_STREAM_CONFIG: {
248 struct msm_audio_stream_config cfg;
249 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
250 rc = -EFAULT;
251 break;
252 }
253 /* Minimum single frame size,
254 but with in maximum frames number */
255 if ((cfg.buffer_size < (audio->min_frame_size+ \
256 sizeof(struct meta_out_dsp))) ||
257 (cfg.buffer_count < FRAME_NUM)) {
258 rc = -EINVAL;
259 break;
260 }
261 audio->str_cfg.buffer_size = cfg.buffer_size;
262 audio->str_cfg.buffer_count = cfg.buffer_count;
Sharad Sangle53049b02013-10-08 21:13:28 +0530263 if(audio->opened){
264 rc = q6asm_audio_client_buf_alloc(OUT,audio->ac,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
266 audio->str_cfg.buffer_count);
Sharad Sangle53049b02013-10-08 21:13:28 +0530267 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
Sharad Sangle53049b02013-10-08 21:13:28 +0530269 __func__, audio->ac->session, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 rc = -ENOMEM;
271 break;
Sharad Sangle53049b02013-10-08 21:13:28 +0530272 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 }
274 audio->buf_alloc |= BUF_ALLOC_OUT;
275 rc = 0;
276 pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
277 __func__, audio->ac->session,
278 audio->str_cfg.buffer_size,
279 audio->str_cfg.buffer_count);
280 break;
281 }
282 case AUDIO_GET_SESSION_ID: {
283 if (copy_to_user((void *) arg, &audio->ac->session,
284 sizeof(unsigned short))) {
285 rc = -EFAULT;
286 }
287 break;
288 }
289 case AUDIO_SET_BUF_CFG: {
290 struct msm_audio_buf_cfg cfg;
291 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
292 rc = -EFAULT;
293 break;
294 }
295 if ((audio->feedback == NON_TUNNEL_MODE) &&
296 !cfg.meta_info_enable) {
297 rc = -EFAULT;
298 break;
299 }
300
301 /* Restrict the num of frames per buf to coincide with
302 * default buf size */
303 if (cfg.frames_per_buf > audio->max_frames_per_buf) {
304 rc = -EFAULT;
305 break;
306 }
307 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
308 audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800309 pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
310 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 audio->ac->session, cfg.meta_info_enable,
312 cfg.frames_per_buf);
313 break;
314 }
315 case AUDIO_GET_BUF_CFG: {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800316 pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
317 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 audio->ac->session, audio->buf_cfg.meta_info_enable,
319 audio->buf_cfg.frames_per_buf);
320
321 if (copy_to_user((void *)arg, &audio->buf_cfg,
322 sizeof(struct msm_audio_buf_cfg)))
323 rc = -EFAULT;
324 break;
325 }
326 case AUDIO_GET_CONFIG: {
327 if (copy_to_user((void *)arg, &audio->pcm_cfg,
328 sizeof(struct msm_audio_config)))
329 rc = -EFAULT;
330 break;
331
332 }
333 case AUDIO_SET_CONFIG: {
334 struct msm_audio_config cfg;
335 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
336 rc = -EFAULT;
337 break;
338 }
339 if (audio->feedback != NON_TUNNEL_MODE) {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800340 pr_err("%s:session id %d: Not sufficient permission to change the record mode\n",
341 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 audio->ac->session);
343 rc = -EACCES;
344 break;
345 }
346 if ((cfg.buffer_count > PCM_BUF_COUNT) ||
347 (cfg.buffer_count == 1))
348 cfg.buffer_count = PCM_BUF_COUNT;
349
350 audio->pcm_cfg.buffer_count = cfg.buffer_count;
351 audio->pcm_cfg.buffer_size = cfg.buffer_size;
352 audio->pcm_cfg.channel_count = cfg.channel_count;
353 audio->pcm_cfg.sample_rate = cfg.sample_rate;
Sharad Sangle53049b02013-10-08 21:13:28 +0530354 if(audio->opened && audio->feedback == NON_TUNNEL_MODE){
355 rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
356 ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
357 audio->pcm_cfg.buffer_count);
358 if(rc < 0){
359 pr_err("%s:session id %d: Buffer Alloc failed\n",
360 __func__,audio->ac->session);
361 rc = -ENOMEM;
362 break;
363 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 }
365 audio->buf_alloc |= BUF_ALLOC_IN;
366 rc = 0;
367 pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
368 audio->ac->session, audio->pcm_cfg.buffer_count,
369 audio->pcm_cfg.buffer_size);
370 break;
371 }
372 default:
373 /* call codec specific ioctl */
374 rc = audio->enc_ioctl(file, cmd, arg);
375 }
376 mutex_unlock(&audio->lock);
377 return rc;
378}
379
380ssize_t audio_in_read(struct file *file,
381 char __user *buf,
382 size_t count, loff_t *pos)
383{
384 struct q6audio_in *audio = file->private_data;
385 const char __user *start = buf;
386 unsigned char *data;
387 uint32_t offset = 0;
388 uint32_t size = 0;
389 int rc = 0;
390 uint32_t idx;
391 struct meta_out_dsp meta;
392 uint32_t bytes_to_copy = 0;
393 uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
394 (sizeof(unsigned char) +
395 (sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
396
397 pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
398 count);
399 if (!audio->enabled)
400 return -EFAULT;
401 mutex_lock(&audio->read_lock);
402 while (count > 0) {
403 rc = wait_event_interruptible(
404 audio->read_wait,
405 ((atomic_read(&audio->out_count) > 0) ||
406 (audio->stopped) ||
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800407 audio->rflush || audio->eos_rsp ||
408 audio->event_abort));
409
410 if (audio->event_abort) {
411 rc = -EIO;
412 break;
413 }
414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415
416 if (rc < 0)
417 break;
418
419 if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
420 audio->rflush) {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800421 pr_debug("%s:session id %d: driver in stop state or flush,No more buf to read",
422 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 audio->ac->session);
424 rc = 0;/* End of File */
425 break;
426 }
427 if (!(atomic_read(&audio->out_count)) &&
428 (audio->eos_rsp == 1) &&
429 (count >= (sizeof(unsigned char) +
430 sizeof(struct meta_out_dsp)))) {
431 unsigned char num_of_frames;
432 pr_info("%s:session id %d: eos %d at output\n",
433 __func__, audio->ac->session, audio->eos_rsp);
434 if (buf != start)
435 break;
436 num_of_frames = 0xFF;
437 if (copy_to_user(buf, &num_of_frames,
438 sizeof(unsigned char))) {
439 rc = -EFAULT;
440 break;
441 }
442 buf += sizeof(unsigned char);
443 meta.frame_size = 0xFFFF;
444 meta.encoded_pcm_samples = 0xFFFF;
445 meta.msw_ts = 0x00;
446 meta.lsw_ts = 0x00;
447 meta.nflags = AUD_EOS_SET;
448 audio->eos_rsp = 0;
449 if (copy_to_user(buf, &meta, sizeof(meta))) {
450 rc = -EFAULT;
451 break;
452 }
453 buf += sizeof(meta);
454 break;
455 }
456 data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
457 &size, &idx);
458 if ((count >= (size + mfield_size)) && data) {
459 if (audio->buf_cfg.meta_info_enable) {
460 if (copy_to_user(buf,
461 &audio->out_frame_info[idx][0],
462 sizeof(unsigned char))) {
463 rc = -EFAULT;
464 break;
465 }
466 bytes_to_copy =
467 (size + audio->out_frame_info[idx][1]);
468 /* Number of frames information copied */
469 buf += sizeof(unsigned char);
470 count -= sizeof(unsigned char);
471 } else {
472 offset = audio->out_frame_info[idx][1];
473 bytes_to_copy = size;
474 }
475
476 pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
477 __func__, audio->ac->session,
478 audio->out_frame_info[idx][1],
479 audio->out_frame_info[idx][0]);
480
481 if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
482 rc = -EFAULT;
483 break;
484 }
485 count -= bytes_to_copy;
486 buf += bytes_to_copy;
487 } else {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800488 pr_err("%s:session id %d: short read data[%p] bytesavail[%d]bytesrequest[%d]\n",
489 __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 audio->ac->session,
491 data, size, count);
492 }
493 atomic_dec(&audio->out_count);
494 q6asm_read(audio->ac);
495 break;
496 }
497 mutex_unlock(&audio->read_lock);
498
499 pr_debug("%s:session id %d: read: %d bytes\n", __func__,
500 audio->ac->session, (buf-start));
501 if (buf > start)
502 return buf - start;
503 return rc;
504}
505
506static int extract_meta_info(char *buf, unsigned long *msw_ts,
507 unsigned long *lsw_ts, unsigned int *flags)
508{
509 struct meta_in *meta = (struct meta_in *)buf;
510 *msw_ts = meta->ntimestamp.highpart;
511 *lsw_ts = meta->ntimestamp.lowpart;
512 *flags = meta->nflags;
513 return 0;
514}
515
516ssize_t audio_in_write(struct file *file,
517 const char __user *buf,
518 size_t count, loff_t *pos)
519{
520 struct q6audio_in *audio = file->private_data;
521 const char __user *start = buf;
522 size_t xfer = 0;
523 char *cpy_ptr;
524 int rc = 0;
525 unsigned char *data;
526 uint32_t size = 0;
527 uint32_t idx = 0;
528 uint32_t nflags = 0;
529 unsigned long msw_ts = 0;
530 unsigned long lsw_ts = 0;
531 uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
532 sizeof(struct meta_in);
533
534 pr_debug("%s:session id %d: to write[%d]\n", __func__,
535 audio->ac->session, count);
536 if (!audio->enabled)
537 return -EFAULT;
538 mutex_lock(&audio->write_lock);
539
540 while (count > 0) {
541 rc = wait_event_interruptible(audio->write_wait,
542 ((atomic_read(&audio->in_count) > 0) ||
543 (audio->stopped) ||
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800544 (audio->wflush) || (audio->event_abort)));
545
546 if (audio->event_abort) {
547 rc = -EIO;
548 break;
549 }
550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 if (rc < 0)
552 break;
553 if (audio->stopped || audio->wflush) {
554 pr_debug("%s: session id %d: stop or flush\n", __func__,
555 audio->ac->session);
556 rc = -EBUSY;
557 break;
558 }
Rajesha Kini72a8b612011-08-10 11:19:55 +0530559 /* if no PCM data, might have only eos buffer
560 such case do not hold cpu buffer */
561 if ((buf == start) && (count == mfield_size)) {
562 char eos_buf[sizeof(struct meta_in)];
563 /* Processing begining of user buffer */
564 if (copy_from_user(eos_buf, buf, mfield_size)) {
565 rc = -EFAULT;
566 break;
567 }
568 /* Check if EOS flag is set and buffer has
569 * contains just meta field
570 */
571 extract_meta_info(eos_buf, &msw_ts, &lsw_ts,
572 &nflags);
573 buf += mfield_size;
574 /* send the EOS and return */
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800575 pr_debug("%s:session id %d: send EOS 0x%8x\n",
576 __func__,
Rajesha Kini72a8b612011-08-10 11:19:55 +0530577 audio->ac->session, nflags);
578 break;
579 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
581 &size, &idx);
582 if (!data) {
583 pr_debug("%s:session id %d: No buf available\n",
584 __func__, audio->ac->session);
585 continue;
586 }
587 cpy_ptr = data;
588 if (audio->buf_cfg.meta_info_enable) {
589 if (buf == start) {
590 /* Processing beginning of user buffer */
591 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
592 rc = -EFAULT;
593 break;
594 }
595 /* Check if EOS flag is set and buffer has
596 * contains just meta field
597 */
598 extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
599 &nflags);
600 buf += mfield_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 count -= mfield_size;
602 } else {
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800603 pr_debug("%s:session id %d: continuous buffer\n",
604 __func__, audio->ac->session);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 }
606 }
607 xfer = (count > (audio->pcm_cfg.buffer_size)) ?
608 (audio->pcm_cfg.buffer_size) : count;
609
610 if (copy_from_user(cpy_ptr, buf, xfer)) {
611 rc = -EFAULT;
612 break;
613 }
614 rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
615 if (rc < 0) {
616 rc = -EFAULT;
617 break;
618 }
619 atomic_dec(&audio->in_count);
620 count -= xfer;
621 buf += xfer;
622 }
623 mutex_unlock(&audio->write_lock);
Phani Kumar Uppalapati4e3c5db2013-01-08 10:54:14 -0800624 pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x] start[0x%x]\n",
625 __func__, audio->ac->session,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 nflags, (int) buf, (int) start);
627 if (nflags & AUD_EOS_SET) {
628 rc = q6asm_cmd(audio->ac, CMD_EOS);
629 pr_info("%s:session id %d: eos %d at input\n", __func__,
630 audio->ac->session, audio->eos_rsp);
631 }
632 pr_debug("%s:session id %d: Written %d Avail Buf[%d]", __func__,
633 audio->ac->session, (buf - start - mfield_size),
634 atomic_read(&audio->in_count));
635 if (!rc) {
636 if (buf > start)
637 return buf - start;
638 }
639 return rc;
640}
641
642int audio_in_release(struct inode *inode, struct file *file)
643{
644 struct q6audio_in *audio = file->private_data;
645 pr_info("%s: session id %d\n", __func__, audio->ac->session);
646 mutex_lock(&audio->lock);
647 audio_in_disable(audio);
648 q6asm_audio_client_free(audio->ac);
649 mutex_unlock(&audio->lock);
650 kfree(audio->enc_cfg);
Harmandeep Singhd7d785c2011-11-15 11:46:26 -0800651 kfree(audio->codec_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 kfree(audio);
653 return 0;
654}
655