Fix common misspellings
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / intel_sst / intel_sst_app_interface.c
CommitLineData
fffa1cca
VK
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
d0f40c50
JP
30#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
fffa1cca
VK
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>
964c6975 38#include <linux/pm_runtime.h>
fffa1cca 39#include <linux/ioctl.h>
fffa1cca
VK
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
60static int intel_sst_check_device(void)
61{
62 int retval = 0;
63 if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) {
d0f40c50 64 pr_warn("Sound card not available\n");
fffa1cca
VK
65 return -EIO;
66 }
67 if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
d0f40c50 68 pr_debug("Resuming from Suspended state\n");
fffa1cca
VK
69 retval = intel_sst_resume(sst_drv_ctx->pci);
70 if (retval) {
d0f40c50 71 pr_debug("Resume Failed= %#x,abort\n", retval);
fffa1cca
VK
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 */
101int intel_sst_open(struct inode *i_node, struct file *file_ptr)
102{
6f6ffec1 103 unsigned int retval;
fffa1cca
VK
104
105 mutex_lock(&sst_drv_ctx->stream_lock);
964c6975 106 pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
6f6ffec1
VK
107 retval = intel_sst_check_device();
108 if (retval) {
964c6975 109 pm_runtime_put(&sst_drv_ctx->pci->dev);
6f6ffec1
VK
110 mutex_unlock(&sst_drv_ctx->stream_lock);
111 return retval;
112 }
113
fffa1cca
VK
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) {
964c6975 118 pm_runtime_put(&sst_drv_ctx->pci->dev);
fffa1cca
VK
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;
d0f40c50 128 pr_debug("pvt_id handle = %d!\n", data->pvt_id);
fffa1cca
VK
129 } else {
130 retval = -EUSERS;
964c6975 131 pm_runtime_put(&sst_drv_ctx->pci->dev);
fffa1cca
VK
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 */
148int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr)
149{
6f6ffec1 150 unsigned int retval;
fffa1cca
VK
151
152 /* audio manager open */
153 mutex_lock(&sst_drv_ctx->stream_lock);
964c6975 154 pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
6f6ffec1
VK
155 retval = intel_sst_check_device();
156 if (retval) {
964c6975 157 pm_runtime_put(&sst_drv_ctx->pci->dev);
6f6ffec1
VK
158 mutex_unlock(&sst_drv_ctx->stream_lock);
159 return retval;
160 }
161
fffa1cca
VK
162 if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) {
163 sst_drv_ctx->am_cnt++;
d0f40c50 164 pr_debug("AM handle opened...\n");
fffa1cca 165 file_ptr->private_data = NULL;
964c6975 166 } else {
fffa1cca 167 retval = -EACCES;
964c6975
VK
168 pm_runtime_put(&sst_drv_ctx->pci->dev);
169 }
fffa1cca
VK
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 */
184int intel_sst_release(struct inode *i_node, struct file *file_ptr)
185{
186 struct ioctl_pvt_data *data = file_ptr->private_data;
187
d0f40c50 188 pr_debug("Release called, closing app handle\n");
fffa1cca
VK
189 mutex_lock(&sst_drv_ctx->stream_lock);
190 sst_drv_ctx->encoded_cnt--;
191 sst_drv_ctx->stream_cnt--;
964c6975 192 pm_runtime_put(&sst_drv_ctx->pci->dev);
fffa1cca
VK
193 mutex_unlock(&sst_drv_ctx->stream_lock);
194 free_stream_context(data->str_id);
195 kfree(data);
196 return 0;
197}
198
199int 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--;
964c6975 204 pm_runtime_put(&sst_drv_ctx->pci->dev);
fffa1cca 205 mutex_unlock(&sst_drv_ctx->stream_lock);
d0f40c50 206 pr_debug("AM handle closed\n");
fffa1cca
VK
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*/
219int 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;
d0f40c50 232 pr_debug("called for stream %d length 0x%x\n", str_id, length);
fffa1cca
VK
233
234 if (length > sst_drv_ctx->mmap_len)
235 return -ENOMEM;
236 if (!sst_drv_ctx->mmap_mem)
237 return -EIO;
238
25985edc 239 /* round it up to the page boundary */
fffa1cca
VK
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
d0f40c50 255 pr_debug("mmap ret 0x%x\n", retval);
fffa1cca
VK
256 return retval;
257}
258
259/* sets mmap data buffers to play/capture*/
260static 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;
08da782b 267 struct snd_sst_mmap_buff_entry *tmp_buf;
fffa1cca 268
d0f40c50 269 pr_debug("called for str_id %d\n", str_id);
fffa1cca
VK
270 retval = sst_validate_strid(str_id);
271 if (retval)
272 return -EINVAL;
fffa1cca
VK
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
08da782b
DC
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
d0f40c50 294 pr_debug("new buffers count %d status %d\n",
fffa1cca 295 mmap_buf->entries, stream->status);
08da782b 296 buf_entry = tmp_buf;
fffa1cca 297 for (i = 0; i < mmap_buf->entries; i++) {
fffa1cca 298 bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
08da782b
DC
299 if (!bufs) {
300 retval = -ENOMEM;
301 goto out_free;
302 }
fffa1cca
VK
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) {
d0f40c50 324 pr_warn("play frames fail\n");
fffa1cca 325 mutex_unlock(&stream->lock);
08da782b
DC
326 retval = -EIO;
327 goto out_free;
fffa1cca
VK
328 }
329 } else if (stream->ops == STREAM_OPS_CAPTURE) {
330 if (sst_capture_frame(str_id) < 0) {
d0f40c50 331 pr_warn("capture frame fail\n");
fffa1cca 332 mutex_unlock(&stream->lock);
08da782b
DC
333 retval = -EIO;
334 goto out_free;
fffa1cca
VK
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;
d0f40c50 348 pr_debug("end of play/rec ioctl bytes = %d!!\n", retval);
08da782b
DC
349
350out_free:
351 kfree(tmp_buf);
fffa1cca
VK
352 return retval;
353}
354
355/*sets user data buffers to play/capture*/
356static 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 */
d0f40c50 373 pr_debug("Stream isn't in started state %d, prev %d\n",
fffa1cca
VK
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) {
d0f40c50 382 pr_warn("play frames failed\n");
fffa1cca
VK
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) {
d0f40c50 388 pr_warn("capture frames failed\n");
fffa1cca
VK
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;
d0f40c50 403 pr_debug("wait returned error...\n");
fffa1cca
VK
404 }
405 return retval;
406}
407
408/* fills kernel list with buffer addresses for SST DSP driver to process*/
409static 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;
388b2b97 414 unsigned long index, mmap_len;
4fc718a4 415 unsigned char __user *bufp;
fffa1cca
VK
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;
388b2b97
DC
435 if (copy_from_user((void *) &rar_handle,
436 iovec[index].iov_base,
437 sizeof(__u32)))
fffa1cca
VK
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) {
388b2b97
DC
473 if (copy_from_user((void *)
474 (stream_bufs->addr + copied_size),
475 bufp, size)) {
fffa1cca
VK
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)) {
d0f40c50 501 pr_debug("Buffer overflows\n");
fffa1cca
VK
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;
d0f40c50 514 pr_debug("copied_size - %lx\n", copied_size);
fffa1cca
VK
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*/
535static 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;
fffa1cca
VK
542
543 /* copy sent buffers */
d0f40c50 544 pr_debug("capture stream copying to user now...\n");
fffa1cca
VK
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) {
4fc718a4 550 if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset,
388b2b97
DC
551 kbufs->addr + entry->offset,
552 entry->size)) {
fffa1cca
VK
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 }
d0f40c50 562 pr_debug("end of cap copy\n");
fffa1cca
VK
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 */
577static 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*/
601static 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) {
d0f40c50 614 pr_warn("user write and stream is mapped\n");
fffa1cca
VK
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 */
d0f40c50 622 pr_debug("new buffers %p, copy size %d, status %d\n" ,
fffa1cca
VK
623 buf, (int) count, (int) stream->status);
624
625 stream->buf_type = SST_BUF_USER_STATIC;
4fc718a4 626 iovec.iov_base = buf;
fffa1cca
VK
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;
d0f40c50 642 pr_debug("end of play/rec bytes = %d!!\n", retval);
fffa1cca
VK
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 */
656int 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
d0f40c50 663 pr_debug("called for %d\n", str_id);
fffa1cca
VK
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 */
681ssize_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
d0f40c50 689 pr_debug("entry - %ld\n", nr_segs);
fffa1cca
VK
690
691 if (is_sync_kiocb(kiocb) == false)
692 return -EINVAL;
693
d0f40c50 694 pr_debug("called for str_id %d\n", str_id);
fffa1cca
VK
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;
d0f40c50 707 pr_debug("new segs %ld, offset %d, status %d\n" ,
fffa1cca
VK
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;
d0f40c50 722 pr_debug("end of play/rec bytes = %d!!\n", retval);
fffa1cca
VK
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 */
736int 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
d0f40c50 743 pr_debug("called for %d\n", str_id);
fffa1cca
VK
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 */
760ssize_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
d0f40c50 768 pr_debug("entry - %ld\n", nr_segs);
fffa1cca
VK
769
770 if (is_sync_kiocb(kiocb) == false) {
d0f40c50 771 pr_debug("aio_read from user space is not allowed\n");
fffa1cca
VK
772 return -EINVAL;
773 }
774
d0f40c50 775 pr_debug("called for str_id %d\n", str_id);
fffa1cca
VK
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
d0f40c50 788 pr_debug("new segs %ld, offset %d, status %d\n" ,
fffa1cca
VK
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;
d0f40c50 803 pr_debug("end of play/rec bytes = %d!!\n", retval);
fffa1cca
VK
804 return retval;
805}
806
807/* sst_print_stream_params - prints the stream parameters (debug fn)*/
808static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm)
809{
d0f40c50 810 pr_debug("codec params:result = %d\n",
fffa1cca 811 get_prm->codec_params.result);
d0f40c50 812 pr_debug("codec params:stream = %d\n",
fffa1cca 813 get_prm->codec_params.stream_id);
d0f40c50 814 pr_debug("codec params:codec = %d\n",
fffa1cca 815 get_prm->codec_params.codec);
d0f40c50 816 pr_debug("codec params:ops = %d\n",
fffa1cca 817 get_prm->codec_params.ops);
d0f40c50 818 pr_debug("codec params:stream_type = %d\n",
fffa1cca 819 get_prm->codec_params.stream_type);
d0f40c50 820 pr_debug("pcmparams:sfreq = %d\n",
fffa1cca 821 get_prm->pcm_params.sfreq);
d0f40c50 822 pr_debug("pcmparams:num_chan = %d\n",
fffa1cca 823 get_prm->pcm_params.num_chan);
d0f40c50 824 pr_debug("pcmparams:pcm_wd_sz = %d\n",
fffa1cca
VK
825 get_prm->pcm_params.pcm_wd_sz);
826 return;
827}
828
62877913
VK
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 */
837int 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 */
859int 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/**
25985edc 874 * intel_sst_ioctl_dsp - receives the device ioctl's
62877913
VK
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 */
882long 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 }
956free_mem:
957 kfree(algo_params_copied->params);
958 kfree(algo_params_copied);
959 break;
960 }
961 return retval;
962}
963
fffa1cca 964/**
d0f40c50 965 * intel_sst_ioctl - receives the device ioctl's
fffa1cca
VK
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 */
973long 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
fffa1cca
VK
979 data = file_ptr->private_data;
980 if (data) {
981 minor = 0;
982 str_id = data->str_id;
983 } else
984 minor = 1;
985
88eea8de 986 if (sst_drv_ctx->sst_state != SST_FW_RUNNING)
fffa1cca 987 return -EBUSY;
fffa1cca
VK
988
989 switch (_IOC_NR(cmd)) {
990 case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
d0f40c50 991 pr_debug("IOCTL_PAUSE received for %d!\n", str_id);
fffa1cca
VK
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):
d0f40c50 1000 pr_debug("SNDRV_SST_IOCTL_RESUME received!\n");
fffa1cca
VK
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): {
bc704e31 1009 struct snd_sst_params str_param;
fffa1cca 1010
d0f40c50 1011 pr_debug("IOCTL_SET_PARAMS received!\n");
fffa1cca
VK
1012 if (minor != STREAM_MODULE) {
1013 retval = -EBADRQC;
1014 break;
1015 }
1016
bc704e31
DC
1017 if (copy_from_user(&str_param, (void __user *)arg,
1018 sizeof(str_param))) {
1019 retval = -EFAULT;
1020 break;
1021 }
1022
fffa1cca
VK
1023 if (!str_id) {
1024
bc704e31 1025 retval = sst_get_stream(&str_param);
fffa1cca
VK
1026 if (retval > 0) {
1027 struct stream_info *str_info;
bc704e31
DC
1028 char __user *dest;
1029
fffa1cca
VK
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;
4fc718a4 1034 dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id);
bc704e31 1035 retval = copy_to_user(dest, &retval, sizeof(__u32));
87b554a0
DC
1036 if (retval)
1037 retval = -EFAULT;
fffa1cca
VK
1038 } else {
1039 if (retval == -SST_ERR_INVALID_PARAMS)
1040 retval = -EINVAL;
1041 }
1042 } else {
d0f40c50 1043 pr_debug("SET_STREAM_PARAMS received!\n");
fffa1cca 1044 /* allocated set params only */
bc704e31 1045 retval = sst_set_stream_param(str_id, &str_param);
fffa1cca
VK
1046 /* Block the call for reply */
1047 if (!retval) {
1048 int sfreq = 0, word_size = 0, num_channel = 0;
bc704e31
DC
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) {
fffa1cca
VK
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): {
3b97eed2
DC
1062 struct snd_sst_vol set_vol;
1063
1064 if (copy_from_user(&set_vol, (void __user *)arg,
1065 sizeof(set_vol))) {
d0f40c50 1066 pr_debug("copy failed\n");
388b2b97 1067 retval = -EFAULT;
fffa1cca
VK
1068 break;
1069 }
25985edc 1070 pr_debug("SET_VOLUME received for %d!\n",
3b97eed2
DC
1071 set_vol.stream_id);
1072 if (minor == STREAM_MODULE && set_vol.stream_id == 0) {
491acf00 1073 pr_debug("invalid operation!\n");
fffa1cca
VK
1074 retval = -EPERM;
1075 break;
1076 }
3b97eed2 1077 retval = sst_set_vol(&set_vol);
fffa1cca
VK
1078 break;
1079 }
1080 case _IOC_NR(SNDRV_SST_GET_VOL): {
fffa1cca 1081 struct snd_sst_vol get_vol;
3b97eed2
DC
1082
1083 if (copy_from_user(&get_vol, (void __user *)arg,
1084 sizeof(get_vol))) {
1085 retval = -EFAULT;
1086 break;
1087 }
25985edc 1088 pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n",
3b97eed2
DC
1089 get_vol.stream_id);
1090 if (minor == STREAM_MODULE && get_vol.stream_id == 0) {
d0f40c50 1091 pr_debug("invalid operation!\n");
fffa1cca
VK
1092 retval = -EPERM;
1093 break;
1094 }
fffa1cca
VK
1095 retval = sst_get_vol(&get_vol);
1096 if (retval) {
1097 retval = -EIO;
1098 break;
1099 }
d0f40c50 1100 pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
fffa1cca
VK
1101 get_vol.stream_id, get_vol.volume,
1102 get_vol.ramp_duration, get_vol.ramp_type);
4fc718a4 1103 if (copy_to_user((struct snd_sst_vol __user *)arg,
388b2b97 1104 &get_vol, sizeof(get_vol))) {
87b554a0 1105 retval = -EFAULT;
fffa1cca
VK
1106 break;
1107 }
1108 /*sst_print_get_vol_info(str_id, &get_vol);*/
1109 break;
1110 }
1111
1112 case _IOC_NR(SNDRV_SST_MUTE): {
3b97eed2
DC
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;
fffa1cca
VK
1118 break;
1119 }
25985edc 1120 pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n",
3b97eed2
DC
1121 set_mute.stream_id);
1122 if (minor == STREAM_MODULE && set_mute.stream_id == 0) {
1123 retval = -EPERM;
fffa1cca
VK
1124 break;
1125 }
3b97eed2 1126 retval = sst_set_mute(&set_mute);
fffa1cca
VK
1127 break;
1128 }
1129 case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
1130 struct snd_sst_get_stream_params get_params;
1131
d0f40c50 1132 pr_debug("IOCTL_GET_PARAMS received!\n");
fffa1cca
VK
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 }
4fc718a4 1143 if (copy_to_user((struct snd_sst_get_stream_params __user *)arg,
388b2b97
DC
1144 &get_params, sizeof(get_params))) {
1145 retval = -EFAULT;
fffa1cca
VK
1146 break;
1147 }
1148 sst_print_stream_params(&get_params);
1149 break;
1150 }
1151
1152 case _IOC_NR(SNDRV_SST_MMAP_PLAY):
bc704e31
DC
1153 case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): {
1154 struct snd_sst_mmap_buffs mmap_buf;
1155
25985edc 1156 pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n");
fffa1cca
VK
1157 if (minor != STREAM_MODULE) {
1158 retval = -EBADRQC;
1159 break;
1160 }
bc704e31
DC
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);
fffa1cca 1167 break;
bc704e31 1168 }
fffa1cca 1169 case _IOC_NR(SNDRV_SST_STREAM_DROP):
d0f40c50 1170 pr_debug("SNDRV_SST_IOCTL_DROP received!\n");
fffa1cca
VK
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): {
fffa1cca
VK
1179 struct snd_sst_tstamp tstamp = {0};
1180 unsigned long long time, freq, mod;
1181
d0f40c50 1182 pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n");
fffa1cca
VK
1183 if (minor != STREAM_MODULE) {
1184 retval = -EBADRQC;
1185 break;
1186 }
1187 memcpy_fromio(&tstamp,
4fc718a4 1188 sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
fffa1cca
VK
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);
bc704e31
DC
1194 if (copy_to_user((void __user *)arg, &time,
1195 sizeof(unsigned long long)))
fffa1cca
VK
1196 retval = -EFAULT;
1197 break;
1198 }
1199
1200 case _IOC_NR(SNDRV_SST_STREAM_START):{
1201 struct stream_info *stream;
1202
d0f40c50 1203 pr_debug("SNDRV_SST_STREAM_START received!\n");
fffa1cca
VK
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;
81a2fff6 1224 mutex_unlock(&stream->lock);
fffa1cca
VK
1225 break;
1226 }
1227 if (retval < 0) {
1228 stream->status = STREAM_INIT;
81a2fff6 1229 mutex_unlock(&stream->lock);
fffa1cca
VK
1230 break;
1231 }
1232 } else {
1233 retval = -EINVAL;
1234 }
81a2fff6 1235 mutex_unlock(&stream->lock);
fffa1cca
VK
1236 break;
1237 }
1238
1239 case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
bc704e31 1240 struct snd_sst_target_device target_device;
fffa1cca 1241
25985edc 1242 pr_debug("SET_TARGET_DEVICE received!\n");
bc704e31
DC
1243 if (copy_from_user(&target_device, (void __user *)arg,
1244 sizeof(target_device))) {
1245 retval = -EFAULT;
1246 break;
1247 }
fffa1cca
VK
1248 if (minor != AM_MODULE) {
1249 retval = -EBADRQC;
1250 break;
1251 }
bc704e31 1252 retval = sst_target_device_select(&target_device);
fffa1cca
VK
1253 break;
1254 }
1255
1256 case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
bc704e31 1257 struct snd_sst_driver_info info;
fffa1cca 1258
25985edc 1259 pr_debug("SNDRV_SST_DRIVER_INFO received\n");
bc704e31 1260 info.version = SST_VERSION_NUM;
fffa1cca 1261 /* hard coding, shud get sumhow later */
bc704e31 1262 info.active_pcm_streams = sst_drv_ctx->stream_cnt -
fffa1cca 1263 sst_drv_ctx->encoded_cnt;
bc704e31
DC
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;
fffa1cca
VK
1271 break;
1272 }
1273
1274 case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
e9f25689
DC
1275 struct snd_sst_dbufs param;
1276 struct snd_sst_dbufs dbufs_local;
fffa1cca 1277 struct snd_sst_buffs ibufs, obufs;
e9f25689
DC
1278 struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
1279 char __user *dest;
fffa1cca 1280
d0f40c50 1281 pr_debug("SNDRV_SST_STREAM_DECODE received\n");
fffa1cca
VK
1282 if (minor != STREAM_MODULE) {
1283 retval = -EBADRQC;
1284 break;
1285 }
e9f25689
DC
1286 if (copy_from_user(&param, (void __user *)arg,
1287 sizeof(param))) {
1288 retval = -EFAULT;
fffa1cca
VK
1289 break;
1290 }
1291
e9f25689 1292 dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
fffa1cca 1293 dbufs_local.output_bytes_produced =
e9f25689
DC
1294 param.output_bytes_produced;
1295
4fc718a4 1296 if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) {
e9f25689
DC
1297 retval = -EFAULT;
1298 break;
fffa1cca 1299 }
4fc718a4 1300 if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) {
e9f25689
DC
1301 retval = -EFAULT;
1302 break;
fffa1cca 1303 }
e9f25689
DC
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;
fffa1cca 1310 }
e9f25689 1311
4fc718a4 1312 if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry,
e9f25689
DC
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
4fc718a4 1320 if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry,
e9f25689
DC
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
fffa1cca 1328 retval = sst_decode(str_id, &dbufs_local);
e9f25689
DC
1329 if (retval) {
1330 retval = -EAGAIN;
1331 goto free_iobufs;
1332 }
1333
4fc718a4 1334 dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
e9f25689 1335 if (copy_to_user(dest,
388b2b97
DC
1336 &dbufs_local.input_bytes_consumed,
1337 sizeof(unsigned long long))) {
e9f25689
DC
1338 retval = -EFAULT;
1339 goto free_iobufs;
fffa1cca 1340 }
e9f25689 1341
4fc718a4 1342 dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
e9f25689 1343 if (copy_to_user(dest,
fffa1cca 1344 &dbufs_local.output_bytes_produced,
388b2b97 1345 sizeof(unsigned long long))) {
e9f25689
DC
1346 retval = -EFAULT;
1347 goto free_iobufs;
fffa1cca 1348 }
e9f25689
DC
1349free_iobufs:
1350 kfree(ibuf_tmp);
1351 kfree(obuf_tmp);
fffa1cca
VK
1352 break;
1353 }
1354
1355 case _IOC_NR(SNDRV_SST_STREAM_DRAIN):
d0f40c50 1356 pr_debug("SNDRV_SST_STREAM_DRAIN received\n");
fffa1cca
VK
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): {
4fc718a4 1365 unsigned long long __user *bytes = (unsigned long long __user *)arg;
fffa1cca
VK
1366 struct snd_sst_tstamp tstamp = {0};
1367
d0f40c50 1368 pr_debug("STREAM_BYTES_DECODED received!\n");
fffa1cca
VK
1369 if (minor != STREAM_MODULE) {
1370 retval = -EINVAL;
1371 break;
1372 }
1373 memcpy_fromio(&tstamp,
4fc718a4 1374 sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
fffa1cca 1375 sizeof(tstamp));
388b2b97
DC
1376 if (copy_to_user(bytes, &tstamp.bytes_processed,
1377 sizeof(*bytes)))
fffa1cca
VK
1378 retval = -EFAULT;
1379 break;
1380 }
1381 case _IOC_NR(SNDRV_SST_FW_INFO): {
1382 struct snd_sst_fw_info *fw_info;
1383
d0f40c50 1384 pr_debug("SNDRV_SST_FW_INFO received\n");
fffa1cca
VK
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 }
4fc718a4 1397 if (copy_to_user((struct snd_sst_dbufs __user *)arg,
388b2b97 1398 fw_info, sizeof(*fw_info))) {
fffa1cca
VK
1399 kfree(fw_info);
1400 retval = -EFAULT;
1401 break;
1402 }
1403 /*sst_print_fw_info(fw_info);*/
1404 kfree(fw_info);
1405 break;
1406 }
62877913
VK
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;
fffa1cca
VK
1415 default:
1416 retval = -EINVAL;
1417 }
d0f40c50 1418 pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval);
fffa1cca
VK
1419 return retval;
1420}
1421