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