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 
intel_sst_check_device(void)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  */
intel_sst_open(struct inode * i_node,struct file * file_ptr)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  */
intel_sst_open_cntrl(struct inode * i_node,struct file * file_ptr)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  */
intel_sst_release(struct inode * i_node,struct file * file_ptr)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 
intel_sst_release_cntrl(struct inode * i_node,struct file * file_ptr)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 */
intel_sst_mmap(struct file * file_ptr,struct vm_area_struct * vma)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 boundary  */
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*/
intel_sst_mmap_play_capture(u32 str_id,struct snd_sst_mmap_buffs * mmap_buf)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*/
intel_sst_play_capture(struct stream_info * stream,int str_id)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*/
snd_sst_fill_kernel_list(struct stream_info * stream,const struct iovec * iovec,unsigned long nr_segs,struct list_head * copy_to_list)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*/
snd_sst_copy_userbuf_capture(struct stream_info * stream,const struct iovec * iovec,struct list_head * copy_to_list)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  */
snd_sst_userbufs_play_cap(const struct iovec * iovec,unsigned long nr_segs,unsigned int str_id,struct stream_info * stream)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*/
intel_sst_read_write(unsigned int str_id,char __user * buf,size_t count)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  */
intel_sst_write(struct file * file_ptr,const char __user * buf,size_t count,loff_t * offset)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  */
intel_sst_aio_write(struct kiocb * kiocb,const struct iovec * iov,unsigned long nr_segs,loff_t offset)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  */
intel_sst_read(struct file * file_ptr,char __user * buf,size_t count,loff_t * offset)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  */
intel_sst_aio_read(struct kiocb * kiocb,const struct iovec * iov,unsigned long nr_segs,loff_t offset)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)*/
sst_print_stream_params(struct snd_sst_get_stream_params * get_prm)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  */
sst_create_algo_ipc(struct snd_ppp_params * algo_params,struct ipc_post ** msg)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  */
sst_send_algo_ipc(struct ipc_post ** msg)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 - receives 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  */
intel_sst_ioctl_dsp(unsigned int cmd,unsigned long arg)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  */
intel_sst_ioctl(struct file * file_ptr,unsigned int cmd,unsigned long arg)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 received 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 received 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 received 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 received!\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 received!\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 received\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 
1422