xen/balloon: Move dec_totalhigh_pages() from __balloon_append() to balloon_append()
[pandora-kernel.git] / drivers / staging / intel_sst / intel_sst_app_interface.c
1 /*
2  *  intel_sst_interface.c - Intel SST Driver for audio engine
3  *
4  *  Copyright (C) 2008-10 Intel Corp
5  *  Authors:    Vinod Koul <vinod.koul@intel.com>
6  *  Harsha Priya <priya.harsha@intel.com>
7  *  Dharageswari R <dharageswari.r@intel.com>
8  *  Jeeja KP <jeeja.kp@intel.com>
9  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; version 2 of the License.
14  *
15  *  This program is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with this program; if not, write to the Free Software Foundation, Inc.,
22  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23  *
24  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25  *  This driver exposes the audio engine functionalities to the ALSA
26  *      and middleware.
27  *  Upper layer interfaces (MAD driver, MMF) to SST driver
28  */
29
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
32 #include <linux/pci.h>
33 #include <linux/fs.h>
34 #include <linux/uio.h>
35 #include <linux/aio.h>
36 #include <linux/uaccess.h>
37 #include <linux/firmware.h>
38 #include <linux/pm_runtime.h>
39 #include <linux/ioctl.h>
40 #ifdef CONFIG_MRST_RAR_HANDLER
41 #include <linux/rar_register.h>
42 #include "../../../drivers/staging/memrar/memrar.h"
43 #endif
44 #include "intel_sst.h"
45 #include "intel_sst_ioctl.h"
46 #include "intel_sst_fw_ipc.h"
47 #include "intel_sst_common.h"
48
49 #define AM_MODULE 1
50 #define STREAM_MODULE 0
51
52
53 /**
54 * intel_sst_check_device - checks SST device
55 *
56 * This utility function checks the state of SST device and downlaods FW if
57 * not done, or resumes the device if suspended
58 */
59
60 static int intel_sst_check_device(void)
61 {
62         int retval = 0;
63         if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) {
64                 pr_warn("Sound card not available\n");
65                 return -EIO;
66         }
67         if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
68                 pr_debug("Resuming from Suspended state\n");
69                 retval = intel_sst_resume(sst_drv_ctx->pci);
70                 if (retval) {
71                         pr_debug("Resume Failed= %#x,abort\n", retval);
72                         return retval;
73                 }
74         }
75
76         if (sst_drv_ctx->sst_state == SST_UN_INIT) {
77                 /* FW is not downloaded */
78                 retval = sst_download_fw();
79                 if (retval)
80                         return -ENODEV;
81                 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
82                         retval = sst_drv_ctx->rx_time_slot_status;
83                         if (retval != RX_TIMESLOT_UNINIT
84                                         && sst_drv_ctx->pmic_vendor != SND_NC)
85                                 sst_enable_rx_timeslot(retval);
86                 }
87         }
88         return 0;
89 }
90
91 /**
92  * intel_sst_open - opens a handle to driver
93  *
94  * @i_node:     inode structure
95  * @file_ptr:pointer to file
96  *
97  * This function is called by OS when a user space component
98  * tries to get a driver handle. Only one handle at a time
99  * will be allowed
100  */
101 int intel_sst_open(struct inode *i_node, struct file *file_ptr)
102 {
103         unsigned int retval;
104
105         mutex_lock(&sst_drv_ctx->stream_lock);
106         pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
107         retval = intel_sst_check_device();
108         if (retval) {
109                 pm_runtime_put(&sst_drv_ctx->pci->dev);
110                 mutex_unlock(&sst_drv_ctx->stream_lock);
111                 return retval;
112         }
113
114         if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) {
115                 struct ioctl_pvt_data *data =
116                         kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL);
117                 if (!data) {
118                         pm_runtime_put(&sst_drv_ctx->pci->dev);
119                         mutex_unlock(&sst_drv_ctx->stream_lock);
120                         return -ENOMEM;
121                 }
122
123                 sst_drv_ctx->encoded_cnt++;
124                 mutex_unlock(&sst_drv_ctx->stream_lock);
125                 data->pvt_id = sst_assign_pvt_id(sst_drv_ctx);
126                 data->str_id = 0;
127                 file_ptr->private_data = (void *)data;
128                 pr_debug("pvt_id handle = %d!\n", data->pvt_id);
129         } else {
130                 retval = -EUSERS;
131                 pm_runtime_put(&sst_drv_ctx->pci->dev);
132                 mutex_unlock(&sst_drv_ctx->stream_lock);
133         }
134         return retval;
135 }
136
137 /**
138  * intel_sst_open_cntrl - opens a handle to driver
139  *
140  * @i_node:     inode structure
141  * @file_ptr:pointer to file
142  *
143  * This function is called by OS when a user space component
144  * tries to get a driver handle to /dev/intel_sst_control.
145  * Only one handle at a time will be allowed
146  * This is for control operations only
147  */
148 int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr)
149 {
150         unsigned int retval;
151
152         /* audio manager open */
153         mutex_lock(&sst_drv_ctx->stream_lock);
154         pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
155         retval = intel_sst_check_device();
156         if (retval) {
157                 pm_runtime_put(&sst_drv_ctx->pci->dev);
158                 mutex_unlock(&sst_drv_ctx->stream_lock);
159                 return retval;
160         }
161
162         if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) {
163                 sst_drv_ctx->am_cnt++;
164                 pr_debug("AM handle opened...\n");
165                 file_ptr->private_data = NULL;
166         } else {
167                 retval = -EACCES;
168                 pm_runtime_put(&sst_drv_ctx->pci->dev);
169         }
170
171         mutex_unlock(&sst_drv_ctx->stream_lock);
172         return retval;
173 }
174
175 /**
176  * intel_sst_release - releases a handle to driver
177  *
178  * @i_node:     inode structure
179  * @file_ptr:   pointer to file
180  *
181  * This function is called by OS when a user space component
182  * tries to release a driver handle.
183  */
184 int intel_sst_release(struct inode *i_node, struct file *file_ptr)
185 {
186         struct ioctl_pvt_data *data = file_ptr->private_data;
187
188         pr_debug("Release called, closing app handle\n");
189         mutex_lock(&sst_drv_ctx->stream_lock);
190         sst_drv_ctx->encoded_cnt--;
191         sst_drv_ctx->stream_cnt--;
192         pm_runtime_put(&sst_drv_ctx->pci->dev);
193         mutex_unlock(&sst_drv_ctx->stream_lock);
194         free_stream_context(data->str_id);
195         kfree(data);
196         return 0;
197 }
198
199 int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr)
200 {
201         /* audio manager close */
202         mutex_lock(&sst_drv_ctx->stream_lock);
203         sst_drv_ctx->am_cnt--;
204         pm_runtime_put(&sst_drv_ctx->pci->dev);
205         mutex_unlock(&sst_drv_ctx->stream_lock);
206         pr_debug("AM handle closed\n");
207         return 0;
208 }
209
210 /**
211 * intel_sst_mmap - mmaps a kernel buffer to user space for copying data
212 *
213 * @vma:         vm area structure instance
214 * @file_ptr:    pointer to file
215 *
216 * This function is called by OS when a user space component
217 * tries to get mmap memory from driver
218 */
219 int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
220 {
221         int retval, length;
222         struct ioctl_pvt_data *data =
223                 (struct ioctl_pvt_data *)file_ptr->private_data;
224         int str_id = data->str_id;
225         void *mem_area;
226
227         retval = sst_validate_strid(str_id);
228         if (retval)
229                 return -EINVAL;
230
231         length = vma->vm_end - vma->vm_start;
232         pr_debug("called for stream %d length 0x%x\n", str_id, length);
233
234         if (length > sst_drv_ctx->mmap_len)
235                 return -ENOMEM;
236         if (!sst_drv_ctx->mmap_mem)
237                 return -EIO;
238
239         /* round it up to the page bondary  */
240         /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem)
241                                 + PAGE_SIZE - 1) & PAGE_MASK);*/
242         mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem);
243
244         /* map the whole physically contiguous area in one piece  */
245         retval = remap_pfn_range(vma,
246                         vma->vm_start,
247                         virt_to_phys((void *)mem_area) >> PAGE_SHIFT,
248                         length,
249                         vma->vm_page_prot);
250         if (retval)
251                 sst_drv_ctx->streams[str_id].mmapped = false;
252         else
253                 sst_drv_ctx->streams[str_id].mmapped = true;
254
255         pr_debug("mmap ret 0x%x\n", retval);
256         return retval;
257 }
258
259 /* sets mmap data buffers to play/capture*/
260 static int intel_sst_mmap_play_capture(u32 str_id,
261                 struct snd_sst_mmap_buffs *mmap_buf)
262 {
263         struct sst_stream_bufs *bufs;
264         int retval, i;
265         struct stream_info *stream;
266         struct snd_sst_mmap_buff_entry *buf_entry;
267         struct snd_sst_mmap_buff_entry *tmp_buf;
268
269         pr_debug("called for str_id %d\n", str_id);
270         retval = sst_validate_strid(str_id);
271         if (retval)
272                 return -EINVAL;
273
274         stream = &sst_drv_ctx->streams[str_id];
275         if (stream->mmapped != true)
276                 return -EIO;
277
278         if (stream->status == STREAM_UN_INIT ||
279                 stream->status == STREAM_DECODE) {
280                 return -EBADRQC;
281         }
282         stream->curr_bytes = 0;
283         stream->cumm_bytes = 0;
284
285         tmp_buf = kcalloc(mmap_buf->entries, sizeof(*tmp_buf), GFP_KERNEL);
286         if (!tmp_buf)
287                 return -ENOMEM;
288         if (copy_from_user(tmp_buf, (void __user *)mmap_buf->buff,
289                         mmap_buf->entries * sizeof(*tmp_buf))) {
290                 retval = -EFAULT;
291                 goto out_free;
292         }
293
294         pr_debug("new buffers count %d status %d\n",
295                         mmap_buf->entries, stream->status);
296         buf_entry = tmp_buf;
297         for (i = 0; i < mmap_buf->entries; i++) {
298                 bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
299                 if (!bufs) {
300                         retval = -ENOMEM;
301                         goto out_free;
302                 }
303                 bufs->size = buf_entry->size;
304                 bufs->offset = buf_entry->offset;
305                 bufs->addr = sst_drv_ctx->mmap_mem;
306                 bufs->in_use = false;
307                 buf_entry++;
308                 /* locking here */
309                 mutex_lock(&stream->lock);
310                 list_add_tail(&bufs->node, &stream->bufs);
311                 mutex_unlock(&stream->lock);
312         }
313
314         mutex_lock(&stream->lock);
315         stream->data_blk.condition = false;
316         stream->data_blk.ret_code = 0;
317         if (stream->status == STREAM_INIT &&
318                         stream->prev != STREAM_UN_INIT &&
319                         stream->need_draining != true) {
320                 stream->prev = stream->status;
321                 stream->status = STREAM_RUNNING;
322                 if (stream->ops == STREAM_OPS_PLAYBACK) {
323                         if (sst_play_frame(str_id) < 0) {
324                                 pr_warn("play frames fail\n");
325                                 mutex_unlock(&stream->lock);
326                                 retval = -EIO;
327                                 goto out_free;
328                         }
329                 } else if (stream->ops == STREAM_OPS_CAPTURE) {
330                         if (sst_capture_frame(str_id) < 0) {
331                                 pr_warn("capture frame fail\n");
332                                 mutex_unlock(&stream->lock);
333                                 retval = -EIO;
334                                 goto out_free;
335                         }
336                 }
337         }
338         mutex_unlock(&stream->lock);
339         /* Block the call for reply */
340         if (!list_empty(&stream->bufs)) {
341                 stream->data_blk.on = true;
342                 retval = sst_wait_interruptible(sst_drv_ctx,
343                                         &stream->data_blk);
344         }
345
346         if (retval >= 0)
347                 retval = stream->cumm_bytes;
348         pr_debug("end of play/rec ioctl bytes = %d!!\n", retval);
349
350 out_free:
351         kfree(tmp_buf);
352         return retval;
353 }
354
355 /*sets user data buffers to play/capture*/
356 static int intel_sst_play_capture(struct stream_info *stream, int str_id)
357 {
358         int retval;
359
360         stream->data_blk.ret_code = 0;
361         stream->data_blk.on = true;
362         stream->data_blk.condition = false;
363
364         mutex_lock(&stream->lock);
365         if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) {
366                 /* stream is started */
367                 stream->prev = stream->status;
368                 stream->status = STREAM_RUNNING;
369         }
370
371         if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) {
372                 /* stream is not started yet */
373                 pr_debug("Stream isn't in started state %d, prev %d\n",
374                         stream->status, stream->prev);
375         } else if ((stream->status == STREAM_RUNNING ||
376                         stream->status == STREAM_PAUSED) &&
377                         stream->need_draining != true) {
378                 /* stream is started */
379                 if (stream->ops == STREAM_OPS_PLAYBACK ||
380                                 stream->ops == STREAM_OPS_PLAYBACK_DRM) {
381                         if (sst_play_frame(str_id) < 0) {
382                                 pr_warn("play frames failed\n");
383                                 mutex_unlock(&stream->lock);
384                                 return -EIO;
385                         }
386                 } else if (stream->ops == STREAM_OPS_CAPTURE) {
387                         if (sst_capture_frame(str_id) < 0) {
388                                 pr_warn("capture frames failed\n");
389                                 mutex_unlock(&stream->lock);
390                                 return -EIO;
391                         }
392                 }
393         } else {
394                 mutex_unlock(&stream->lock);
395                 return -EIO;
396         }
397         mutex_unlock(&stream->lock);
398         /* Block the call for reply */
399
400         retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk);
401         if (retval) {
402                 stream->status = STREAM_INIT;
403                 pr_debug("wait returned error...\n");
404         }
405         return retval;
406 }
407
408 /* fills kernel list with buffer addresses for SST DSP driver to process*/
409 static int snd_sst_fill_kernel_list(struct stream_info *stream,
410                         const struct iovec *iovec, unsigned long nr_segs,
411                         struct list_head *copy_to_list)
412 {
413         struct sst_stream_bufs *stream_bufs;
414         unsigned long index, mmap_len;
415         unsigned char __user *bufp;
416         unsigned long size, copied_size;
417         int retval = 0, add_to_list = 0;
418         static int sent_offset;
419         static unsigned long sent_index;
420
421         stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
422         if (!stream_bufs)
423                 return -ENOMEM;
424         stream_bufs->addr = sst_drv_ctx->mmap_mem;
425 #ifdef CONFIG_MRST_RAR_HANDLER
426         if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
427                 for (index = stream->sg_index; index < nr_segs; index++) {
428                         __u32 rar_handle;
429                         struct sst_stream_bufs *stream_bufs =
430                                 kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
431
432                         stream->sg_index = index;
433                         if (!stream_bufs)
434                                 return -ENOMEM;
435                         if (copy_from_user((void *) &rar_handle,
436                                         iovec[index].iov_base,
437                                         sizeof(__u32)))
438                                 return -EFAULT;
439                         stream_bufs->addr = (char *)rar_handle;
440                         stream_bufs->in_use = false;
441                         stream_bufs->size = iovec[0].iov_len;
442                         /* locking here */
443                         mutex_lock(&stream->lock);
444                         list_add_tail(&stream_bufs->node, &stream->bufs);
445                         mutex_unlock(&stream->lock);
446                 }
447                 stream->sg_index = index;
448                 return retval;
449         }
450 #endif
451         mmap_len = sst_drv_ctx->mmap_len;
452         stream_bufs->addr = sst_drv_ctx->mmap_mem;
453         bufp = stream->cur_ptr;
454
455         copied_size = 0;
456
457         if (!stream->sg_index)
458                 sent_index = sent_offset = 0;
459
460         for (index = stream->sg_index; index < nr_segs; index++) {
461                 stream->sg_index = index;
462                 if (!stream->cur_ptr)
463                         bufp = iovec[index].iov_base;
464
465                 size = ((unsigned long)iovec[index].iov_base
466                         + iovec[index].iov_len) - (unsigned long) bufp;
467
468                 if ((copied_size + size) > mmap_len)
469                         size = mmap_len - copied_size;
470
471
472                 if (stream->ops == STREAM_OPS_PLAYBACK) {
473                         if (copy_from_user((void *)
474                                         (stream_bufs->addr + copied_size),
475                                         bufp, size)) {
476                                 /* Clean up the list and return error code */
477                                 retval = -EFAULT;
478                                 break;
479                         }
480                 } else if (stream->ops == STREAM_OPS_CAPTURE) {
481                         struct snd_sst_user_cap_list *entry =
482                                 kzalloc(sizeof(*entry), GFP_KERNEL);
483
484                         if (!entry) {
485                                 kfree(stream_bufs);
486                                 return -ENOMEM;
487                         }
488                         entry->iov_index = index;
489                         entry->iov_offset = (unsigned long) bufp -
490                                         (unsigned long)iovec[index].iov_base;
491                         entry->offset = copied_size;
492                         entry->size = size;
493                         list_add_tail(&entry->node, copy_to_list);
494                 }
495
496                 stream->cur_ptr = bufp + size;
497
498                 if (((unsigned long)iovec[index].iov_base
499                                 + iovec[index].iov_len) <
500                                 ((unsigned long)iovec[index].iov_base)) {
501                         pr_debug("Buffer overflows\n");
502                         kfree(stream_bufs);
503                         return -EINVAL;
504                 }
505
506                 if (((unsigned long)iovec[index].iov_base
507                                         + iovec[index].iov_len) ==
508                                         (unsigned long)stream->cur_ptr) {
509                         stream->cur_ptr = NULL;
510                         stream->sg_index++;
511                 }
512
513                 copied_size += size;
514                 pr_debug("copied_size - %lx\n", copied_size);
515                 if ((copied_size >= mmap_len) ||
516                                 (stream->sg_index == nr_segs)) {
517                         add_to_list = 1;
518                 }
519
520                 if (add_to_list) {
521                         stream_bufs->in_use = false;
522                         stream_bufs->size = copied_size;
523                         /* locking here */
524                         mutex_lock(&stream->lock);
525                         list_add_tail(&stream_bufs->node, &stream->bufs);
526                         mutex_unlock(&stream->lock);
527                         break;
528                 }
529         }
530         return retval;
531 }
532
533 /* This function copies the captured data returned from SST DSP engine
534  * to the user buffers*/
535 static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
536                         const struct iovec *iovec,
537                         struct list_head *copy_to_list)
538 {
539         struct snd_sst_user_cap_list *entry, *_entry;
540         struct sst_stream_bufs *kbufs = NULL, *_kbufs;
541         int retval = 0;
542
543         /* copy sent buffers */
544         pr_debug("capture stream copying to user now...\n");
545         list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
546                 if (kbufs->in_use == true) {
547                         /* copy to user */
548                         list_for_each_entry_safe(entry, _entry,
549                                                 copy_to_list, node) {
550                                 if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset,
551                                              kbufs->addr + entry->offset,
552                                              entry->size)) {
553                                         /* Clean up the list and return error */
554                                         retval = -EFAULT;
555                                         break;
556                                 }
557                                 list_del(&entry->node);
558                                 kfree(entry);
559                         }
560                 }
561         }
562         pr_debug("end of cap copy\n");
563         return retval;
564 }
565
566 /*
567  * snd_sst_userbufs_play_cap - constructs the list from user buffers
568  *
569  * @iovec:pointer to iovec structure
570  * @nr_segs:number entries in the iovec structure
571  * @str_id:stream id
572  * @stream:pointer to stream_info structure
573  *
574  * This function will traverse the user list and copy the data to the kernel
575  * space buffers.
576  */
577 static int snd_sst_userbufs_play_cap(const struct iovec *iovec,
578                         unsigned long nr_segs, unsigned int str_id,
579                         struct stream_info *stream)
580 {
581         int retval;
582         LIST_HEAD(copy_to_list);
583
584
585         retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs,
586                        &copy_to_list);
587
588         retval = intel_sst_play_capture(stream, str_id);
589         if (retval < 0)
590                 return retval;
591
592         if (stream->ops == STREAM_OPS_CAPTURE) {
593                 retval = snd_sst_copy_userbuf_capture(stream, iovec,
594                                 &copy_to_list);
595         }
596         return retval;
597 }
598
599 /* This function is common function across read/write
600   for user buffers called from system calls*/
601 static int intel_sst_read_write(unsigned int str_id, char __user *buf,
602                                         size_t count)
603 {
604         int retval;
605         struct stream_info *stream;
606         struct iovec iovec;
607         unsigned long nr_segs;
608
609         retval = sst_validate_strid(str_id);
610         if (retval)
611                 return -EINVAL;
612         stream = &sst_drv_ctx->streams[str_id];
613         if (stream->mmapped == true) {
614                 pr_warn("user write and stream is mapped\n");
615                 return -EIO;
616         }
617         if (!count)
618                 return -EINVAL;
619         stream->curr_bytes = 0;
620         stream->cumm_bytes = 0;
621         /* copy user buf details */
622         pr_debug("new buffers %p, copy size %d, status %d\n" ,
623                         buf, (int) count, (int) stream->status);
624
625         stream->buf_type = SST_BUF_USER_STATIC;
626         iovec.iov_base = buf;
627         iovec.iov_len  = count;
628         nr_segs = 1;
629
630         do {
631                 retval = snd_sst_userbufs_play_cap(
632                                 &iovec, nr_segs, str_id, stream);
633                 if (retval < 0)
634                         break;
635
636         } while (stream->sg_index < nr_segs);
637
638         stream->sg_index = 0;
639         stream->cur_ptr = NULL;
640         if (retval >= 0)
641                 retval = stream->cumm_bytes;
642         pr_debug("end of play/rec bytes = %d!!\n", retval);
643         return retval;
644 }
645
646 /***
647  * intel_sst_write - This function is called when user tries to play out data
648  *
649  * @file_ptr:pointer to file
650  * @buf:user buffer to be played out
651  * @count:size of tthe buffer
652  * @offset:offset to start from
653  *
654  * writes the encoded data into DSP
655  */
656 int intel_sst_write(struct file *file_ptr, const char __user *buf,
657                         size_t count, loff_t *offset)
658 {
659         struct ioctl_pvt_data *data = file_ptr->private_data;
660         int str_id = data->str_id;
661         struct stream_info *stream = &sst_drv_ctx->streams[str_id];
662
663         pr_debug("called for %d\n", str_id);
664         if (stream->status == STREAM_UN_INIT ||
665                 stream->status == STREAM_DECODE) {
666                 return -EBADRQC;
667         }
668         return intel_sst_read_write(str_id, (char __user *)buf, count);
669 }
670
671 /*
672  * intel_sst_aio_write - write buffers
673  *
674  * @kiocb:pointer to a structure containing file pointer
675  * @iov:list of user buffer to be played out
676  * @nr_segs:number of entries
677  * @offset:offset to start from
678  *
679  * This function is called when user tries to play out multiple data buffers
680  */
681 ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
682                         unsigned long nr_segs, loff_t  offset)
683 {
684         int retval;
685         struct ioctl_pvt_data *data = kiocb->ki_filp->private_data;
686         int str_id = data->str_id;
687         struct stream_info *stream;
688
689         pr_debug("entry - %ld\n", nr_segs);
690
691         if (is_sync_kiocb(kiocb) == false)
692                 return -EINVAL;
693
694         pr_debug("called for str_id %d\n", str_id);
695         retval = sst_validate_strid(str_id);
696         if (retval)
697                 return -EINVAL;
698         stream = &sst_drv_ctx->streams[str_id];
699         if (stream->mmapped == true)
700                 return -EIO;
701         if (stream->status == STREAM_UN_INIT ||
702                 stream->status == STREAM_DECODE) {
703                 return -EBADRQC;
704         }
705         stream->curr_bytes = 0;
706         stream->cumm_bytes = 0;
707         pr_debug("new segs %ld, offset %d, status %d\n" ,
708                         nr_segs, (int) offset, (int) stream->status);
709         stream->buf_type = SST_BUF_USER_STATIC;
710         do {
711                 retval = snd_sst_userbufs_play_cap(iov, nr_segs,
712                                                 str_id, stream);
713                 if (retval < 0)
714                         break;
715
716         } while (stream->sg_index < nr_segs);
717
718         stream->sg_index = 0;
719         stream->cur_ptr = NULL;
720         if (retval >= 0)
721                 retval = stream->cumm_bytes;
722         pr_debug("end of play/rec bytes = %d!!\n", retval);
723         return retval;
724 }
725
726 /*
727  * intel_sst_read - read the encoded data
728  *
729  * @file_ptr: pointer to file
730  * @buf: user buffer to be filled with captured data
731  * @count: size of tthe buffer
732  * @offset: offset to start from
733  *
734  * This function is called when user tries to capture data
735  */
736 int intel_sst_read(struct file *file_ptr, char __user *buf,
737                         size_t count, loff_t *offset)
738 {
739         struct ioctl_pvt_data *data = file_ptr->private_data;
740         int str_id = data->str_id;
741         struct stream_info *stream = &sst_drv_ctx->streams[str_id];
742
743         pr_debug("called for %d\n", str_id);
744         if (stream->status == STREAM_UN_INIT ||
745                         stream->status == STREAM_DECODE)
746                 return -EBADRQC;
747         return intel_sst_read_write(str_id, buf, count);
748 }
749
750 /*
751  * intel_sst_aio_read - aio read
752  *
753  * @kiocb: pointer to a structure containing file pointer
754  * @iov: list of user buffer to be filled with captured
755  * @nr_segs: number of entries
756  * @offset: offset to start from
757  *
758  * This function is called when user tries to capture out multiple data buffers
759  */
760 ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
761                          unsigned long nr_segs, loff_t offset)
762 {
763         int retval;
764         struct ioctl_pvt_data *data = kiocb->ki_filp->private_data;
765         int str_id = data->str_id;
766         struct stream_info *stream;
767
768         pr_debug("entry - %ld\n", nr_segs);
769
770         if (is_sync_kiocb(kiocb) == false) {
771                 pr_debug("aio_read from user space is not allowed\n");
772                 return -EINVAL;
773         }
774
775         pr_debug("called for str_id %d\n", str_id);
776         retval = sst_validate_strid(str_id);
777         if (retval)
778                 return -EINVAL;
779         stream = &sst_drv_ctx->streams[str_id];
780         if (stream->mmapped == true)
781                 return -EIO;
782         if (stream->status == STREAM_UN_INIT ||
783                         stream->status == STREAM_DECODE)
784                 return -EBADRQC;
785         stream->curr_bytes = 0;
786         stream->cumm_bytes = 0;
787
788         pr_debug("new segs %ld, offset %d, status %d\n" ,
789                         nr_segs, (int) offset, (int) stream->status);
790         stream->buf_type = SST_BUF_USER_STATIC;
791         do {
792                 retval = snd_sst_userbufs_play_cap(iov, nr_segs,
793                                                 str_id, stream);
794                 if (retval < 0)
795                         break;
796
797         } while (stream->sg_index < nr_segs);
798
799         stream->sg_index = 0;
800         stream->cur_ptr = NULL;
801         if (retval >= 0)
802                 retval = stream->cumm_bytes;
803         pr_debug("end of play/rec bytes = %d!!\n", retval);
804         return retval;
805 }
806
807 /* sst_print_stream_params - prints the stream parameters (debug fn)*/
808 static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm)
809 {
810         pr_debug("codec params:result = %d\n",
811                                 get_prm->codec_params.result);
812         pr_debug("codec params:stream = %d\n",
813                                 get_prm->codec_params.stream_id);
814         pr_debug("codec params:codec = %d\n",
815                                 get_prm->codec_params.codec);
816         pr_debug("codec params:ops = %d\n",
817                                 get_prm->codec_params.ops);
818         pr_debug("codec params:stream_type = %d\n",
819                                 get_prm->codec_params.stream_type);
820         pr_debug("pcmparams:sfreq = %d\n",
821                                 get_prm->pcm_params.sfreq);
822         pr_debug("pcmparams:num_chan = %d\n",
823                                 get_prm->pcm_params.num_chan);
824         pr_debug("pcmparams:pcm_wd_sz = %d\n",
825                                 get_prm->pcm_params.pcm_wd_sz);
826         return;
827 }
828
829 /**
830  * sst_create_algo_ipc - create ipc msg for algorithm parameters
831  *
832  * @algo_params: Algorithm parameters
833  * @msg: post msg pointer
834  *
835  * This function is called to create ipc msg
836  */
837 int sst_create_algo_ipc(struct snd_ppp_params *algo_params,
838                                         struct ipc_post **msg)
839 {
840         if (sst_create_large_msg(msg))
841                 return -ENOMEM;
842         sst_fill_header(&(*msg)->header,
843                         IPC_IA_ALG_PARAMS, 1, algo_params->str_id);
844         (*msg)->header.part.data = sizeof(u32) +
845                         sizeof(*algo_params) + algo_params->size;
846         memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32));
847         memcpy((*msg)->mailbox_data + sizeof(u32),
848                                 algo_params, sizeof(*algo_params));
849         return 0;
850 }
851
852 /**
853  * sst_send_algo_ipc - send ipc msg for algorithm parameters
854  *
855  * @msg: post msg pointer
856  *
857  * This function is called to send ipc msg
858  */
859 int sst_send_algo_ipc(struct ipc_post **msg)
860 {
861         sst_drv_ctx->ppp_params_blk.condition = false;
862         sst_drv_ctx->ppp_params_blk.ret_code = 0;
863         sst_drv_ctx->ppp_params_blk.on = true;
864         sst_drv_ctx->ppp_params_blk.data = NULL;
865         spin_lock(&sst_drv_ctx->list_spin_lock);
866         list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list);
867         spin_unlock(&sst_drv_ctx->list_spin_lock);
868         sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
869         return sst_wait_interruptible_timeout(sst_drv_ctx,
870                         &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT);
871 }
872
873 /**
874  * intel_sst_ioctl_dsp - recieves the device ioctl's
875  *
876  * @cmd:Ioctl cmd
877  * @arg:data
878  *
879  * This function is called when a user space component
880  * sends a DSP Ioctl to SST driver
881  */
882 long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg)
883 {
884         int retval = 0;
885         struct snd_ppp_params algo_params;
886         struct snd_ppp_params *algo_params_copied;
887         struct ipc_post *msg;
888
889         switch (_IOC_NR(cmd)) {
890         case _IOC_NR(SNDRV_SST_SET_ALGO):
891                 if (copy_from_user(&algo_params, (void __user *)arg,
892                                                         sizeof(algo_params)))
893                         return -EFAULT;
894                 if (algo_params.size > SST_MAILBOX_SIZE)
895                         return -EMSGSIZE;
896
897                 pr_debug("Algo ID %d Str id %d Enable %d Size %d\n",
898                         algo_params.algo_id, algo_params.str_id,
899                         algo_params.enable, algo_params.size);
900                 retval = sst_create_algo_ipc(&algo_params, &msg);
901                 if (retval)
902                         break;
903                 algo_params.reserved = 0;
904                 if (copy_from_user(msg->mailbox_data + sizeof(algo_params),
905                                 algo_params.params, algo_params.size))
906                         return -EFAULT;
907
908                 retval = sst_send_algo_ipc(&msg);
909                 if (retval) {
910                         pr_debug("Error in sst_set_algo = %d\n", retval);
911                         retval = -EIO;
912                 }
913                 break;
914
915         case _IOC_NR(SNDRV_SST_GET_ALGO):
916                 if (copy_from_user(&algo_params, (void __user *)arg,
917                                                         sizeof(algo_params)))
918                         return -EFAULT;
919                 pr_debug("Algo ID %d Str id %d Enable %d Size %d\n",
920                         algo_params.algo_id, algo_params.str_id,
921                         algo_params.enable, algo_params.size);
922                 retval = sst_create_algo_ipc(&algo_params, &msg);
923                 if (retval)
924                         break;
925                 algo_params.reserved = 1;
926                 retval = sst_send_algo_ipc(&msg);
927                 if (retval) {
928                         pr_debug("Error in sst_get_algo = %d\n", retval);
929                         retval = -EIO;
930                         break;
931                 }
932                 algo_params_copied = (struct snd_ppp_params *)
933                                         sst_drv_ctx->ppp_params_blk.data;
934                 if (algo_params_copied->size > algo_params.size) {
935                         pr_debug("mem insufficient to copy\n");
936                         retval = -EMSGSIZE;
937                         goto free_mem;
938                 } else {
939                         char __user *tmp;
940
941                         if (copy_to_user(algo_params.params,
942                                         algo_params_copied->params,
943                                         algo_params_copied->size)) {
944                                 retval = -EFAULT;
945                                 goto free_mem;
946                         }
947                         tmp = (char __user *)arg + offsetof(
948                                         struct snd_ppp_params, size);
949                         if (copy_to_user(tmp, &algo_params_copied->size,
950                                                  sizeof(__u32))) {
951                                 retval = -EFAULT;
952                                 goto free_mem;
953                         }
954
955                 }
956 free_mem:
957                 kfree(algo_params_copied->params);
958                 kfree(algo_params_copied);
959                 break;
960         }
961         return retval;
962 }
963
964 /**
965  * intel_sst_ioctl - receives the device ioctl's
966  * @file_ptr:pointer to file
967  * @cmd:Ioctl cmd
968  * @arg:data
969  *
970  * This function is called by OS when a user space component
971  * sends an Ioctl to SST driver
972  */
973 long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
974 {
975         int retval = 0;
976         struct ioctl_pvt_data *data = NULL;
977         int str_id = 0, minor = 0;
978
979         data = file_ptr->private_data;
980         if (data) {
981                 minor = 0;
982                 str_id = data->str_id;
983         } else
984                 minor = 1;
985
986         if (sst_drv_ctx->sst_state != SST_FW_RUNNING)
987                 return -EBUSY;
988
989         switch (_IOC_NR(cmd)) {
990         case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
991                 pr_debug("IOCTL_PAUSE received for %d!\n", str_id);
992                 if (minor != STREAM_MODULE) {
993                         retval = -EBADRQC;
994                         break;
995                 }
996                 retval = sst_pause_stream(str_id);
997                 break;
998
999         case _IOC_NR(SNDRV_SST_STREAM_RESUME):
1000                 pr_debug("SNDRV_SST_IOCTL_RESUME received!\n");
1001                 if (minor != STREAM_MODULE) {
1002                         retval = -EBADRQC;
1003                         break;
1004                 }
1005                 retval = sst_resume_stream(str_id);
1006                 break;
1007
1008         case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
1009                 struct snd_sst_params str_param;
1010
1011                 pr_debug("IOCTL_SET_PARAMS received!\n");
1012                 if (minor != STREAM_MODULE) {
1013                         retval = -EBADRQC;
1014                         break;
1015                 }
1016
1017                 if (copy_from_user(&str_param, (void __user *)arg,
1018                                 sizeof(str_param))) {
1019                         retval = -EFAULT;
1020                         break;
1021                 }
1022
1023                 if (!str_id) {
1024
1025                         retval = sst_get_stream(&str_param);
1026                         if (retval > 0) {
1027                                 struct stream_info *str_info;
1028                                 char __user *dest;
1029
1030                                 sst_drv_ctx->stream_cnt++;
1031                                 data->str_id = retval;
1032                                 str_info = &sst_drv_ctx->streams[retval];
1033                                 str_info->src = SST_DRV;
1034                                 dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id);
1035                                 retval = copy_to_user(dest, &retval, sizeof(__u32));
1036                                 if (retval)
1037                                         retval = -EFAULT;
1038                         } else {
1039                                 if (retval == -SST_ERR_INVALID_PARAMS)
1040                                         retval = -EINVAL;
1041                         }
1042                 } else {
1043                         pr_debug("SET_STREAM_PARAMS received!\n");
1044                         /* allocated set params only */
1045                         retval = sst_set_stream_param(str_id, &str_param);
1046                         /* Block the call for reply */
1047                         if (!retval) {
1048                                 int sfreq = 0, word_size = 0, num_channel = 0;
1049                                 sfreq = str_param.sparams.uc.pcm_params.sfreq;
1050                                 word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz;
1051                                 num_channel = str_param.sparams.uc.pcm_params.num_chan;
1052                                 if (str_param.ops == STREAM_OPS_CAPTURE) {
1053                                         sst_drv_ctx->scard_ops->\
1054                                         set_pcm_audio_params(sfreq,
1055                                                 word_size, num_channel);
1056                                 }
1057                         }
1058                 }
1059                 break;
1060         }
1061         case _IOC_NR(SNDRV_SST_SET_VOL): {
1062                 struct snd_sst_vol set_vol;
1063
1064                 if (copy_from_user(&set_vol, (void __user *)arg,
1065                                 sizeof(set_vol))) {
1066                         pr_debug("copy failed\n");
1067                         retval = -EFAULT;
1068                         break;
1069                 }
1070                 pr_debug("SET_VOLUME recieved for %d!\n",
1071                                 set_vol.stream_id);
1072                 if (minor == STREAM_MODULE && set_vol.stream_id == 0) {
1073                         pr_debug("invalid operation!\n");
1074                         retval = -EPERM;
1075                         break;
1076                 }
1077                 retval = sst_set_vol(&set_vol);
1078                 break;
1079         }
1080         case _IOC_NR(SNDRV_SST_GET_VOL): {
1081                 struct snd_sst_vol get_vol;
1082
1083                 if (copy_from_user(&get_vol, (void __user *)arg,
1084                                 sizeof(get_vol))) {
1085                         retval = -EFAULT;
1086                         break;
1087                 }
1088                 pr_debug("IOCTL_GET_VOLUME recieved for stream = %d!\n",
1089                                 get_vol.stream_id);
1090                 if (minor == STREAM_MODULE && get_vol.stream_id == 0) {
1091                         pr_debug("invalid operation!\n");
1092                         retval = -EPERM;
1093                         break;
1094                 }
1095                 retval = sst_get_vol(&get_vol);
1096                 if (retval) {
1097                         retval = -EIO;
1098                         break;
1099                 }
1100                 pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
1101                                 get_vol.stream_id, get_vol.volume,
1102                                 get_vol.ramp_duration, get_vol.ramp_type);
1103                 if (copy_to_user((struct snd_sst_vol __user *)arg,
1104                                 &get_vol, sizeof(get_vol))) {
1105                         retval = -EFAULT;
1106                         break;
1107                 }
1108                 /*sst_print_get_vol_info(str_id, &get_vol);*/
1109                 break;
1110         }
1111
1112         case _IOC_NR(SNDRV_SST_MUTE): {
1113                 struct snd_sst_mute set_mute;
1114
1115                 if (copy_from_user(&set_mute, (void __user *)arg,
1116                                 sizeof(set_mute))) {
1117                         retval = -EFAULT;
1118                         break;
1119                 }
1120                 pr_debug("SNDRV_SST_SET_VOLUME recieved for %d!\n",
1121                         set_mute.stream_id);
1122                 if (minor == STREAM_MODULE && set_mute.stream_id == 0) {
1123                         retval = -EPERM;
1124                         break;
1125                 }
1126                 retval = sst_set_mute(&set_mute);
1127                 break;
1128         }
1129         case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
1130                 struct snd_sst_get_stream_params get_params;
1131
1132                 pr_debug("IOCTL_GET_PARAMS received!\n");
1133                 if (minor != 0) {
1134                         retval = -EBADRQC;
1135                         break;
1136                 }
1137
1138                 retval = sst_get_stream_params(str_id, &get_params);
1139                 if (retval) {
1140                         retval = -EIO;
1141                         break;
1142                 }
1143                 if (copy_to_user((struct snd_sst_get_stream_params __user *)arg,
1144                                         &get_params, sizeof(get_params))) {
1145                         retval = -EFAULT;
1146                         break;
1147                 }
1148                 sst_print_stream_params(&get_params);
1149                 break;
1150         }
1151
1152         case _IOC_NR(SNDRV_SST_MMAP_PLAY):
1153         case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): {
1154                 struct snd_sst_mmap_buffs mmap_buf;
1155
1156                 pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
1157                 if (minor != STREAM_MODULE) {
1158                         retval = -EBADRQC;
1159                         break;
1160                 }
1161                 if (copy_from_user(&mmap_buf, (void __user *)arg,
1162                                 sizeof(mmap_buf))) {
1163                         retval = -EFAULT;
1164                         break;
1165                 }
1166                 retval = intel_sst_mmap_play_capture(str_id, &mmap_buf);
1167                 break;
1168         }
1169         case _IOC_NR(SNDRV_SST_STREAM_DROP):
1170                 pr_debug("SNDRV_SST_IOCTL_DROP received!\n");
1171                 if (minor != STREAM_MODULE) {
1172                         retval = -EINVAL;
1173                         break;
1174                 }
1175                 retval = sst_drop_stream(str_id);
1176                 break;
1177
1178         case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): {
1179                 struct snd_sst_tstamp tstamp = {0};
1180                 unsigned long long time, freq, mod;
1181
1182                 pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n");
1183                 if (minor != STREAM_MODULE) {
1184                         retval = -EBADRQC;
1185                         break;
1186                 }
1187                 memcpy_fromio(&tstamp,
1188                         sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
1189                         sizeof(tstamp));
1190                 time = tstamp.samples_rendered;
1191                 freq = (unsigned long long) tstamp.sampling_frequency;
1192                 time = time * 1000; /* converting it to ms */
1193                 mod = do_div(time, freq);
1194                 if (copy_to_user((void __user *)arg, &time,
1195                                 sizeof(unsigned long long)))
1196                         retval = -EFAULT;
1197                 break;
1198         }
1199
1200         case _IOC_NR(SNDRV_SST_STREAM_START):{
1201                 struct stream_info *stream;
1202
1203                 pr_debug("SNDRV_SST_STREAM_START received!\n");
1204                 if (minor != STREAM_MODULE) {
1205                         retval = -EINVAL;
1206                         break;
1207                 }
1208                 retval = sst_validate_strid(str_id);
1209                 if (retval)
1210                         break;
1211                 stream = &sst_drv_ctx->streams[str_id];
1212                 mutex_lock(&stream->lock);
1213                 if (stream->status == STREAM_INIT &&
1214                         stream->need_draining != true) {
1215                         stream->prev = stream->status;
1216                         stream->status = STREAM_RUNNING;
1217                         if (stream->ops == STREAM_OPS_PLAYBACK ||
1218                                 stream->ops == STREAM_OPS_PLAYBACK_DRM) {
1219                                 retval = sst_play_frame(str_id);
1220                         } else if (stream->ops == STREAM_OPS_CAPTURE)
1221                                 retval = sst_capture_frame(str_id);
1222                         else {
1223                                 retval = -EINVAL;
1224                                 mutex_unlock(&stream->lock);
1225                                 break;
1226                         }
1227                         if (retval < 0) {
1228                                 stream->status = STREAM_INIT;
1229                                 mutex_unlock(&stream->lock);
1230                                 break;
1231                         }
1232                 } else {
1233                         retval = -EINVAL;
1234                 }
1235                 mutex_unlock(&stream->lock);
1236                 break;
1237         }
1238
1239         case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
1240                 struct snd_sst_target_device target_device;
1241
1242                 pr_debug("SET_TARGET_DEVICE recieved!\n");
1243                 if (copy_from_user(&target_device, (void __user *)arg,
1244                                 sizeof(target_device))) {
1245                         retval = -EFAULT;
1246                         break;
1247                 }
1248                 if (minor != AM_MODULE) {
1249                         retval = -EBADRQC;
1250                         break;
1251                 }
1252                 retval = sst_target_device_select(&target_device);
1253                 break;
1254         }
1255
1256         case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
1257                 struct snd_sst_driver_info info;
1258
1259                 pr_debug("SNDRV_SST_DRIVER_INFO recived\n");
1260                 info.version = SST_VERSION_NUM;
1261                 /* hard coding, shud get sumhow later */
1262                 info.active_pcm_streams = sst_drv_ctx->stream_cnt -
1263                                                 sst_drv_ctx->encoded_cnt;
1264                 info.active_enc_streams = sst_drv_ctx->encoded_cnt;
1265                 info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
1266                 info.max_enc_streams = MAX_ENC_STREAM;
1267                 info.buf_per_stream = sst_drv_ctx->mmap_len;
1268                 if (copy_to_user((void __user *)arg, &info,
1269                                 sizeof(info)))
1270                         retval = -EFAULT;
1271                 break;
1272         }
1273
1274         case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
1275                 struct snd_sst_dbufs param;
1276                 struct snd_sst_dbufs dbufs_local;
1277                 struct snd_sst_buffs ibufs, obufs;
1278                 struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
1279                 char __user *dest;
1280
1281                 pr_debug("SNDRV_SST_STREAM_DECODE received\n");
1282                 if (minor != STREAM_MODULE) {
1283                         retval = -EBADRQC;
1284                         break;
1285                 }
1286                 if (copy_from_user(&param, (void __user *)arg,
1287                                 sizeof(param))) {
1288                         retval = -EFAULT;
1289                         break;
1290                 }
1291
1292                 dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
1293                 dbufs_local.output_bytes_produced =
1294                                         param.output_bytes_produced;
1295
1296                 if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) {
1297                         retval = -EFAULT;
1298                         break;
1299                 }
1300                 if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) {
1301                         retval = -EFAULT;
1302                         break;
1303                 }
1304
1305                 ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL);
1306                 obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL);
1307                 if (!ibuf_tmp || !obuf_tmp) {
1308                         retval = -ENOMEM;
1309                         goto free_iobufs;
1310                 }
1311
1312                 if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry,
1313                                 ibufs.entries * sizeof(*ibuf_tmp))) {
1314                         retval = -EFAULT;
1315                         goto free_iobufs;
1316                 }
1317                 ibufs.buff_entry = ibuf_tmp;
1318                 dbufs_local.ibufs = &ibufs;
1319
1320                 if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry,
1321                                 obufs.entries * sizeof(*obuf_tmp))) {
1322                         retval = -EFAULT;
1323                         goto free_iobufs;
1324                 }
1325                 obufs.buff_entry = obuf_tmp;
1326                 dbufs_local.obufs = &obufs;
1327
1328                 retval = sst_decode(str_id, &dbufs_local);
1329                 if (retval) {
1330                         retval = -EAGAIN;
1331                         goto free_iobufs;
1332                 }
1333
1334                 dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
1335                 if (copy_to_user(dest,
1336                                 &dbufs_local.input_bytes_consumed,
1337                                 sizeof(unsigned long long))) {
1338                         retval = -EFAULT;
1339                         goto free_iobufs;
1340                 }
1341
1342                 dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
1343                 if (copy_to_user(dest,
1344                                 &dbufs_local.output_bytes_produced,
1345                                 sizeof(unsigned long long))) {
1346                         retval = -EFAULT;
1347                         goto free_iobufs;
1348                 }
1349 free_iobufs:
1350                 kfree(ibuf_tmp);
1351                 kfree(obuf_tmp);
1352                 break;
1353         }
1354
1355         case _IOC_NR(SNDRV_SST_STREAM_DRAIN):
1356                 pr_debug("SNDRV_SST_STREAM_DRAIN received\n");
1357                 if (minor != STREAM_MODULE) {
1358                         retval = -EINVAL;
1359                         break;
1360                 }
1361                 retval = sst_drain_stream(str_id);
1362                 break;
1363
1364         case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): {
1365                 unsigned long long __user *bytes = (unsigned long long __user *)arg;
1366                 struct snd_sst_tstamp tstamp = {0};
1367
1368                 pr_debug("STREAM_BYTES_DECODED received!\n");
1369                 if (minor != STREAM_MODULE) {
1370                         retval = -EINVAL;
1371                         break;
1372                 }
1373                 memcpy_fromio(&tstamp,
1374                         sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
1375                         sizeof(tstamp));
1376                 if (copy_to_user(bytes, &tstamp.bytes_processed,
1377                                 sizeof(*bytes)))
1378                         retval = -EFAULT;
1379                 break;
1380         }
1381         case _IOC_NR(SNDRV_SST_FW_INFO): {
1382                 struct snd_sst_fw_info *fw_info;
1383
1384                 pr_debug("SNDRV_SST_FW_INFO received\n");
1385
1386                 fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC);
1387                 if (!fw_info) {
1388                         retval = -ENOMEM;
1389                         break;
1390                 }
1391                 retval = sst_get_fw_info(fw_info);
1392                 if (retval) {
1393                         retval = -EIO;
1394                         kfree(fw_info);
1395                         break;
1396                 }
1397                 if (copy_to_user((struct snd_sst_dbufs __user *)arg,
1398                                 fw_info, sizeof(*fw_info))) {
1399                         kfree(fw_info);
1400                         retval = -EFAULT;
1401                         break;
1402                 }
1403                 /*sst_print_fw_info(fw_info);*/
1404                 kfree(fw_info);
1405                 break;
1406         }
1407         case _IOC_NR(SNDRV_SST_GET_ALGO):
1408         case _IOC_NR(SNDRV_SST_SET_ALGO):
1409                 if (minor != AM_MODULE) {
1410                         retval = -EBADRQC;
1411                         break;
1412                 }
1413                 retval = intel_sst_ioctl_dsp(cmd, arg);
1414                 break;
1415         default:
1416                 retval = -EINVAL;
1417         }
1418         pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval);
1419         return retval;
1420 }
1421