diff options
Diffstat (limited to 'drivers/staging/intel_sst/intel_sst_app_interface.c')
-rw-r--r-- | drivers/staging/intel_sst/intel_sst_app_interface.c | 1460 |
1 files changed, 0 insertions, 1460 deletions
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c deleted file mode 100644 index 93b41a284d83..000000000000 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ /dev/null @@ -1,1460 +0,0 @@ -/* - * intel_sst_interface.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * Upper layer interfaces (MAD driver, MMF) to SST driver - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/uio.h> -#include <linux/aio.h> -#include <linux/uaccess.h> -#include <linux/firmware.h> -#include <linux/pm_runtime.h> -#include <linux/ioctl.h> -#ifdef CONFIG_MRST_RAR_HANDLER -#include <linux/rar_register.h> -#include "../../../drivers/staging/memrar/memrar.h" -#endif -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - -#define AM_MODULE 1 -#define STREAM_MODULE 0 - - -/** -* intel_sst_check_device - checks SST device -* -* This utility function checks the state of SST device and downlaods FW if -* not done, or resumes the device if suspended -*/ - -static int intel_sst_check_device(void) -{ - int retval = 0; - if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) { - pr_warn("Sound card not available\n"); - return -EIO; - } - if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - pr_debug("Resuming from Suspended state\n"); - retval = intel_sst_resume(sst_drv_ctx->pci); - if (retval) { - pr_debug("Resume Failed= %#x,abort\n", retval); - return retval; - } - } - - if (sst_drv_ctx->sst_state == SST_UN_INIT) { - /* FW is not downloaded */ - retval = sst_download_fw(); - if (retval) - return -ENODEV; - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - retval = sst_drv_ctx->rx_time_slot_status; - if (retval != RX_TIMESLOT_UNINIT - && sst_drv_ctx->pmic_vendor != SND_NC) - sst_enable_rx_timeslot(retval); - } - } - return 0; -} - -/** - * intel_sst_open - opens a handle to driver - * - * @i_node: inode structure - * @file_ptr:pointer to file - * - * This function is called by OS when a user space component - * tries to get a driver handle. Only one handle at a time - * will be allowed - */ -int intel_sst_open(struct inode *i_node, struct file *file_ptr) -{ - unsigned int retval; - - mutex_lock(&sst_drv_ctx->stream_lock); - pm_runtime_get_sync(&sst_drv_ctx->pci->dev); - retval = intel_sst_check_device(); - if (retval) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; - } - - if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) { - struct ioctl_pvt_data *data = - kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL); - if (!data) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return -ENOMEM; - } - - sst_drv_ctx->encoded_cnt++; - mutex_unlock(&sst_drv_ctx->stream_lock); - data->pvt_id = sst_assign_pvt_id(sst_drv_ctx); - data->str_id = 0; - file_ptr->private_data = (void *)data; - pr_debug("pvt_id handle = %d!\n", data->pvt_id); - } else { - retval = -EUSERS; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - } - return retval; -} - -/** - * intel_sst_open_cntrl - opens a handle to driver - * - * @i_node: inode structure - * @file_ptr:pointer to file - * - * This function is called by OS when a user space component - * tries to get a driver handle to /dev/intel_sst_control. - * Only one handle at a time will be allowed - * This is for control operations only - */ -int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) -{ - unsigned int retval; - - /* audio manager open */ - mutex_lock(&sst_drv_ctx->stream_lock); - pm_runtime_get_sync(&sst_drv_ctx->pci->dev); - retval = intel_sst_check_device(); - if (retval) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; - } - - if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) { - sst_drv_ctx->am_cnt++; - pr_debug("AM handle opened...\n"); - file_ptr->private_data = NULL; - } else { - retval = -EACCES; - pm_runtime_put(&sst_drv_ctx->pci->dev); - } - - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; -} - -/** - * intel_sst_release - releases a handle to driver - * - * @i_node: inode structure - * @file_ptr: pointer to file - * - * This function is called by OS when a user space component - * tries to release a driver handle. - */ -int intel_sst_release(struct inode *i_node, struct file *file_ptr) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - - pr_debug("Release called, closing app handle\n"); - mutex_lock(&sst_drv_ctx->stream_lock); - sst_drv_ctx->encoded_cnt--; - sst_drv_ctx->stream_cnt--; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - free_stream_context(data->str_id); - kfree(data); - return 0; -} - -int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr) -{ - /* audio manager close */ - mutex_lock(&sst_drv_ctx->stream_lock); - sst_drv_ctx->am_cnt--; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - pr_debug("AM handle closed\n"); - return 0; -} - -/** -* intel_sst_mmap - mmaps a kernel buffer to user space for copying data -* -* @vma: vm area structure instance -* @file_ptr: pointer to file -* -* This function is called by OS when a user space component -* tries to get mmap memory from driver -*/ -int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) -{ - int retval, length; - struct ioctl_pvt_data *data = - (struct ioctl_pvt_data *)file_ptr->private_data; - int str_id = data->str_id; - void *mem_area; - - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - - length = vma->vm_end - vma->vm_start; - pr_debug("called for stream %d length 0x%x\n", str_id, length); - - if (length > sst_drv_ctx->mmap_len) - return -ENOMEM; - if (!sst_drv_ctx->mmap_mem) - return -EIO; - - /* round it up to the page boundary */ - /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem) - + PAGE_SIZE - 1) & PAGE_MASK);*/ - mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem); - - /* map the whole physically contiguous area in one piece */ - retval = remap_pfn_range(vma, - vma->vm_start, - virt_to_phys((void *)mem_area) >> PAGE_SHIFT, - length, - vma->vm_page_prot); - if (retval) - sst_drv_ctx->streams[str_id].mmapped = false; - else - sst_drv_ctx->streams[str_id].mmapped = true; - - pr_debug("mmap ret 0x%x\n", retval); - return retval; -} - -/* sets mmap data buffers to play/capture*/ -static int intel_sst_mmap_play_capture(u32 str_id, - struct snd_sst_mmap_buffs *mmap_buf) -{ - struct sst_stream_bufs *bufs; - int retval, i; - struct stream_info *stream; - struct snd_sst_mmap_buff_entry *buf_entry; - struct snd_sst_mmap_buff_entry *tmp_buf; - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped != true) - return -EIO; - - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - - tmp_buf = kcalloc(mmap_buf->entries, sizeof(*tmp_buf), GFP_KERNEL); - if (!tmp_buf) - return -ENOMEM; - if (copy_from_user(tmp_buf, (void __user *)mmap_buf->buff, - mmap_buf->entries * sizeof(*tmp_buf))) { - retval = -EFAULT; - goto out_free; - } - - pr_debug("new buffers count %d status %d\n", - mmap_buf->entries, stream->status); - buf_entry = tmp_buf; - for (i = 0; i < mmap_buf->entries; i++) { - bufs = kzalloc(sizeof(*bufs), GFP_KERNEL); - if (!bufs) { - retval = -ENOMEM; - goto out_free; - } - bufs->size = buf_entry->size; - bufs->offset = buf_entry->offset; - bufs->addr = sst_drv_ctx->mmap_mem; - bufs->in_use = false; - buf_entry++; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - } - - mutex_lock(&stream->lock); - stream->data_blk.condition = false; - stream->data_blk.ret_code = 0; - if (stream->status == STREAM_INIT && - stream->prev != STREAM_UN_INIT && - stream->need_draining != true) { - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - if (stream->ops == STREAM_OPS_PLAYBACK) { - if (sst_play_frame(str_id) < 0) { - pr_warn("play frames fail\n"); - mutex_unlock(&stream->lock); - retval = -EIO; - goto out_free; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - if (sst_capture_frame(str_id) < 0) { - pr_warn("capture frame fail\n"); - mutex_unlock(&stream->lock); - retval = -EIO; - goto out_free; - } - } - } - mutex_unlock(&stream->lock); - /* Block the call for reply */ - if (!list_empty(&stream->bufs)) { - stream->data_blk.on = true; - retval = sst_wait_interruptible(sst_drv_ctx, - &stream->data_blk); - } - - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec ioctl bytes = %d!!\n", retval); - -out_free: - kfree(tmp_buf); - return retval; -} - -/*sets user data buffers to play/capture*/ -static int intel_sst_play_capture(struct stream_info *stream, int str_id) -{ - int retval; - - stream->data_blk.ret_code = 0; - stream->data_blk.on = true; - stream->data_blk.condition = false; - - mutex_lock(&stream->lock); - if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) { - /* stream is started */ - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - } - - if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) { - /* stream is not started yet */ - pr_debug("Stream isn't in started state %d, prev %d\n", - stream->status, stream->prev); - } else if ((stream->status == STREAM_RUNNING || - stream->status == STREAM_PAUSED) && - stream->need_draining != true) { - /* stream is started */ - if (stream->ops == STREAM_OPS_PLAYBACK || - stream->ops == STREAM_OPS_PLAYBACK_DRM) { - if (sst_play_frame(str_id) < 0) { - pr_warn("play frames failed\n"); - mutex_unlock(&stream->lock); - return -EIO; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - if (sst_capture_frame(str_id) < 0) { - pr_warn("capture frames failed\n"); - mutex_unlock(&stream->lock); - return -EIO; - } - } - } else { - mutex_unlock(&stream->lock); - return -EIO; - } - mutex_unlock(&stream->lock); - /* Block the call for reply */ - - retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk); - if (retval) { - stream->status = STREAM_INIT; - pr_debug("wait returned error...\n"); - } - return retval; -} - -/* fills kernel list with buffer addresses for SST DSP driver to process*/ -static int snd_sst_fill_kernel_list(struct stream_info *stream, - const struct iovec *iovec, unsigned long nr_segs, - struct list_head *copy_to_list) -{ - struct sst_stream_bufs *stream_bufs; - unsigned long index, mmap_len; - unsigned char __user *bufp; - unsigned long size, copied_size; - int retval = 0, add_to_list = 0; - static int sent_offset; - static unsigned long sent_index; - -#ifdef CONFIG_MRST_RAR_HANDLER - if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { - for (index = stream->sg_index; index < nr_segs; index++) { - __u32 rar_handle; - struct sst_stream_bufs *stream_bufs = - kzalloc(sizeof(*stream_bufs), GFP_KERNEL); - - stream->sg_index = index; - if (!stream_bufs) - return -ENOMEM; - if (copy_from_user((void *) &rar_handle, - iovec[index].iov_base, - sizeof(__u32))) { - kfree(stream_bufs); - return -EFAULT; - } - stream_bufs->addr = (char *)rar_handle; - stream_bufs->in_use = false; - stream_bufs->size = iovec[0].iov_len; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&stream_bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - } - stream->sg_index = index; - return retval; - } -#endif - stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL); - if (!stream_bufs) - return -ENOMEM; - stream_bufs->addr = sst_drv_ctx->mmap_mem; - mmap_len = sst_drv_ctx->mmap_len; - stream_bufs->addr = sst_drv_ctx->mmap_mem; - bufp = stream->cur_ptr; - - copied_size = 0; - - if (!stream->sg_index) - sent_index = sent_offset = 0; - - for (index = stream->sg_index; index < nr_segs; index++) { - stream->sg_index = index; - if (!stream->cur_ptr) - bufp = iovec[index].iov_base; - - size = ((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) - (unsigned long) bufp; - - if ((copied_size + size) > mmap_len) - size = mmap_len - copied_size; - - - if (stream->ops == STREAM_OPS_PLAYBACK) { - if (copy_from_user((void *) - (stream_bufs->addr + copied_size), - bufp, size)) { - /* Clean up the list and return error code */ - retval = -EFAULT; - break; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - struct snd_sst_user_cap_list *entry = - kzalloc(sizeof(*entry), GFP_KERNEL); - - if (!entry) { - kfree(stream_bufs); - return -ENOMEM; - } - entry->iov_index = index; - entry->iov_offset = (unsigned long) bufp - - (unsigned long)iovec[index].iov_base; - entry->offset = copied_size; - entry->size = size; - list_add_tail(&entry->node, copy_to_list); - } - - stream->cur_ptr = bufp + size; - - if (((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) < - ((unsigned long)iovec[index].iov_base)) { - pr_debug("Buffer overflows\n"); - kfree(stream_bufs); - return -EINVAL; - } - - if (((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) == - (unsigned long)stream->cur_ptr) { - stream->cur_ptr = NULL; - stream->sg_index++; - } - - copied_size += size; - pr_debug("copied_size - %lx\n", copied_size); - if ((copied_size >= mmap_len) || - (stream->sg_index == nr_segs)) { - add_to_list = 1; - } - - if (add_to_list) { - stream_bufs->in_use = false; - stream_bufs->size = copied_size; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&stream_bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - break; - } - } - return retval; -} - -/* This function copies the captured data returned from SST DSP engine - * to the user buffers*/ -static int snd_sst_copy_userbuf_capture(struct stream_info *stream, - const struct iovec *iovec, - struct list_head *copy_to_list) -{ - struct snd_sst_user_cap_list *entry, *_entry; - struct sst_stream_bufs *kbufs = NULL, *_kbufs; - int retval = 0; - - /* copy sent buffers */ - pr_debug("capture stream copying to user now...\n"); - list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { - if (kbufs->in_use == true) { - /* copy to user */ - list_for_each_entry_safe(entry, _entry, - copy_to_list, node) { - if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset, - kbufs->addr + entry->offset, - entry->size)) { - /* Clean up the list and return error */ - retval = -EFAULT; - break; - } - list_del(&entry->node); - kfree(entry); - } - } - } - pr_debug("end of cap copy\n"); - return retval; -} - -/* - * snd_sst_userbufs_play_cap - constructs the list from user buffers - * - * @iovec:pointer to iovec structure - * @nr_segs:number entries in the iovec structure - * @str_id:stream id - * @stream:pointer to stream_info structure - * - * This function will traverse the user list and copy the data to the kernel - * space buffers. - */ -static int snd_sst_userbufs_play_cap(const struct iovec *iovec, - unsigned long nr_segs, unsigned int str_id, - struct stream_info *stream) -{ - int retval; - LIST_HEAD(copy_to_list); - - - retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs, - ©_to_list); - - retval = intel_sst_play_capture(stream, str_id); - if (retval < 0) - return retval; - - if (stream->ops == STREAM_OPS_CAPTURE) { - retval = snd_sst_copy_userbuf_capture(stream, iovec, - ©_to_list); - } - return retval; -} - -/* This function is common function across read/write - for user buffers called from system calls*/ -static int intel_sst_read_write(unsigned int str_id, char __user *buf, - size_t count) -{ - int retval; - struct stream_info *stream; - struct iovec iovec; - unsigned long nr_segs; - - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) { - pr_warn("user write and stream is mapped\n"); - return -EIO; - } - if (!count) - return -EINVAL; - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - /* copy user buf details */ - pr_debug("new buffers %p, copy size %d, status %d\n" , - buf, (int) count, (int) stream->status); - - stream->buf_type = SST_BUF_USER_STATIC; - iovec.iov_base = buf; - iovec.iov_len = count; - nr_segs = 1; - - do { - retval = snd_sst_userbufs_play_cap( - &iovec, nr_segs, str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/*** - * intel_sst_write - This function is called when user tries to play out data - * - * @file_ptr:pointer to file - * @buf:user buffer to be played out - * @count:size of tthe buffer - * @offset:offset to start from - * - * writes the encoded data into DSP - */ -int intel_sst_write(struct file *file_ptr, const char __user *buf, - size_t count, loff_t *offset) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - int str_id = data->str_id; - struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - - pr_debug("called for %d\n", str_id); - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - return intel_sst_read_write(str_id, (char __user *)buf, count); -} - -/* - * intel_sst_aio_write - write buffers - * - * @kiocb:pointer to a structure containing file pointer - * @iov:list of user buffer to be played out - * @nr_segs:number of entries - * @offset:offset to start from - * - * This function is called when user tries to play out multiple data buffers - */ -ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset) -{ - int retval; - struct ioctl_pvt_data *data = kiocb->ki_filp->private_data; - int str_id = data->str_id; - struct stream_info *stream; - - pr_debug("entry - %ld\n", nr_segs); - - if (is_sync_kiocb(kiocb) == false) - return -EINVAL; - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) - return -EIO; - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - pr_debug("new segs %ld, offset %d, status %d\n" , - nr_segs, (int) offset, (int) stream->status); - stream->buf_type = SST_BUF_USER_STATIC; - do { - retval = snd_sst_userbufs_play_cap(iov, nr_segs, - str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/* - * intel_sst_read - read the encoded data - * - * @file_ptr: pointer to file - * @buf: user buffer to be filled with captured data - * @count: size of tthe buffer - * @offset: offset to start from - * - * This function is called when user tries to capture data - */ -int intel_sst_read(struct file *file_ptr, char __user *buf, - size_t count, loff_t *offset) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - int str_id = data->str_id; - struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - - pr_debug("called for %d\n", str_id); - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) - return -EBADRQC; - return intel_sst_read_write(str_id, buf, count); -} - -/* - * intel_sst_aio_read - aio read - * - * @kiocb: pointer to a structure containing file pointer - * @iov: list of user buffer to be filled with captured - * @nr_segs: number of entries - * @offset: offset to start from - * - * This function is called when user tries to capture out multiple data buffers - */ -ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset) -{ - int retval; - struct ioctl_pvt_data *data = kiocb->ki_filp->private_data; - int str_id = data->str_id; - struct stream_info *stream; - - pr_debug("entry - %ld\n", nr_segs); - - if (is_sync_kiocb(kiocb) == false) { - pr_debug("aio_read from user space is not allowed\n"); - return -EINVAL; - } - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) - return -EIO; - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) - return -EBADRQC; - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - - pr_debug("new segs %ld, offset %d, status %d\n" , - nr_segs, (int) offset, (int) stream->status); - stream->buf_type = SST_BUF_USER_STATIC; - do { - retval = snd_sst_userbufs_play_cap(iov, nr_segs, - str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/* sst_print_stream_params - prints the stream parameters (debug fn)*/ -static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) -{ - pr_debug("codec params:result = %d\n", - get_prm->codec_params.result); - pr_debug("codec params:stream = %d\n", - get_prm->codec_params.stream_id); - pr_debug("codec params:codec = %d\n", - get_prm->codec_params.codec); - pr_debug("codec params:ops = %d\n", - get_prm->codec_params.ops); - pr_debug("codec params:stream_type = %d\n", - get_prm->codec_params.stream_type); - pr_debug("pcmparams:sfreq = %d\n", - get_prm->pcm_params.sfreq); - pr_debug("pcmparams:num_chan = %d\n", - get_prm->pcm_params.num_chan); - pr_debug("pcmparams:pcm_wd_sz = %d\n", - get_prm->pcm_params.pcm_wd_sz); - return; -} - -/** - * sst_create_algo_ipc - create ipc msg for algorithm parameters - * - * @algo_params: Algorithm parameters - * @msg: post msg pointer - * - * This function is called to create ipc msg - */ -int sst_create_algo_ipc(struct snd_ppp_params *algo_params, - struct ipc_post **msg) -{ - if (sst_create_large_msg(msg)) - return -ENOMEM; - sst_fill_header(&(*msg)->header, - IPC_IA_ALG_PARAMS, 1, algo_params->str_id); - (*msg)->header.part.data = sizeof(u32) + - sizeof(*algo_params) + algo_params->size; - memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32)); - memcpy((*msg)->mailbox_data + sizeof(u32), - algo_params, sizeof(*algo_params)); - return 0; -} - -/** - * sst_send_algo_ipc - send ipc msg for algorithm parameters - * - * @msg: post msg pointer - * - * This function is called to send ipc msg - */ -int sst_send_algo_ipc(struct ipc_post **msg) -{ - sst_drv_ctx->ppp_params_blk.condition = false; - sst_drv_ctx->ppp_params_blk.ret_code = 0; - sst_drv_ctx->ppp_params_blk.on = true; - sst_drv_ctx->ppp_params_blk.data = NULL; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT); -} - -/** - * intel_sst_ioctl_dsp - receives the device ioctl's - * - * @cmd:Ioctl cmd - * @arg:data - * - * This function is called when a user space component - * sends a DSP Ioctl to SST driver - */ -long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg) -{ - int retval = 0; - struct snd_ppp_params algo_params; - struct snd_ppp_params *algo_params_copied; - struct ipc_post *msg; - - switch (_IOC_NR(cmd)) { - case _IOC_NR(SNDRV_SST_SET_ALGO): - if (copy_from_user(&algo_params, (void __user *)arg, - sizeof(algo_params))) - return -EFAULT; - if (algo_params.size > SST_MAILBOX_SIZE) - return -EMSGSIZE; - - pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", - algo_params.algo_id, algo_params.str_id, - algo_params.enable, algo_params.size); - retval = sst_create_algo_ipc(&algo_params, &msg); - if (retval) - break; - algo_params.reserved = 0; - if (copy_from_user(msg->mailbox_data + sizeof(algo_params), - algo_params.params, algo_params.size)) - return -EFAULT; - - retval = sst_send_algo_ipc(&msg); - if (retval) { - pr_debug("Error in sst_set_algo = %d\n", retval); - retval = -EIO; - } - break; - - case _IOC_NR(SNDRV_SST_GET_ALGO): - if (copy_from_user(&algo_params, (void __user *)arg, - sizeof(algo_params))) - return -EFAULT; - pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", - algo_params.algo_id, algo_params.str_id, - algo_params.enable, algo_params.size); - retval = sst_create_algo_ipc(&algo_params, &msg); - if (retval) - break; - algo_params.reserved = 1; - retval = sst_send_algo_ipc(&msg); - if (retval) { - pr_debug("Error in sst_get_algo = %d\n", retval); - retval = -EIO; - break; - } - algo_params_copied = (struct snd_ppp_params *) - sst_drv_ctx->ppp_params_blk.data; - if (algo_params_copied->size > algo_params.size) { - pr_debug("mem insufficient to copy\n"); - retval = -EMSGSIZE; - goto free_mem; - } else { - char __user *tmp; - - if (copy_to_user(algo_params.params, - algo_params_copied->params, - algo_params_copied->size)) { - retval = -EFAULT; - goto free_mem; - } - tmp = (char __user *)arg + offsetof( - struct snd_ppp_params, size); - if (copy_to_user(tmp, &algo_params_copied->size, - sizeof(__u32))) { - retval = -EFAULT; - goto free_mem; - } - - } -free_mem: - kfree(algo_params_copied->params); - kfree(algo_params_copied); - break; - } - return retval; -} - - -int sst_ioctl_tuning_params(unsigned long arg) -{ - struct snd_sst_tuning_params params; - struct ipc_post *msg; - - if (copy_from_user(¶ms, (void __user *)arg, sizeof(params))) - return -EFAULT; - if (params.size > SST_MAILBOX_SIZE) - return -ENOMEM; - pr_debug("Parameter %d, Stream %d, Size %d\n", params.type, - params.str_id, params.size); - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_TUNING_PARAMS, 1, params.str_id); - msg->header.part.data = sizeof(u32) + sizeof(params) + params.size; - memcpy(msg->mailbox_data, &msg->header.full, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), ¶ms, sizeof(params)); - if (copy_from_user(msg->mailbox_data + sizeof(params), - (void __user *)(unsigned long)params.addr, - params.size)) { - kfree(msg->mailbox_data); - kfree(msg); - return -EFAULT; - } - return sst_send_algo_ipc(&msg); -} -/** - * intel_sst_ioctl - receives the device ioctl's - * @file_ptr:pointer to file - * @cmd:Ioctl cmd - * @arg:data - * - * This function is called by OS when a user space component - * sends an Ioctl to SST driver - */ -long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - struct ioctl_pvt_data *data = NULL; - int str_id = 0, minor = 0; - - data = file_ptr->private_data; - if (data) { - minor = 0; - str_id = data->str_id; - } else - minor = 1; - - if (sst_drv_ctx->sst_state != SST_FW_RUNNING) - return -EBUSY; - - switch (_IOC_NR(cmd)) { - case _IOC_NR(SNDRV_SST_STREAM_PAUSE): - pr_debug("IOCTL_PAUSE received for %d!\n", str_id); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_pause_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_RESUME): - pr_debug("SNDRV_SST_IOCTL_RESUME received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_resume_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): { - struct snd_sst_params str_param; - - pr_debug("IOCTL_SET_PARAMS received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - - if (copy_from_user(&str_param, (void __user *)arg, - sizeof(str_param))) { - retval = -EFAULT; - break; - } - - if (!str_id) { - - retval = sst_get_stream(&str_param); - if (retval > 0) { - struct stream_info *str_info; - char __user *dest; - - sst_drv_ctx->stream_cnt++; - data->str_id = retval; - str_info = &sst_drv_ctx->streams[retval]; - str_info->src = SST_DRV; - dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id); - retval = copy_to_user(dest, &retval, sizeof(__u32)); - if (retval) - retval = -EFAULT; - } else { - if (retval == -SST_ERR_INVALID_PARAMS) - retval = -EINVAL; - } - } else { - pr_debug("SET_STREAM_PARAMS received!\n"); - /* allocated set params only */ - retval = sst_set_stream_param(str_id, &str_param); - /* Block the call for reply */ - if (!retval) { - int sfreq = 0, word_size = 0, num_channel = 0; - sfreq = str_param.sparams.uc.pcm_params.sfreq; - word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz; - num_channel = str_param.sparams.uc.pcm_params.num_chan; - if (str_param.ops == STREAM_OPS_CAPTURE) { - sst_drv_ctx->scard_ops->\ - set_pcm_audio_params(sfreq, - word_size, num_channel); - } - } - } - break; - } - case _IOC_NR(SNDRV_SST_SET_VOL): { - struct snd_sst_vol set_vol; - - if (copy_from_user(&set_vol, (void __user *)arg, - sizeof(set_vol))) { - pr_debug("copy failed\n"); - retval = -EFAULT; - break; - } - pr_debug("SET_VOLUME received for %d!\n", - set_vol.stream_id); - if (minor == STREAM_MODULE && set_vol.stream_id == 0) { - pr_debug("invalid operation!\n"); - retval = -EPERM; - break; - } - retval = sst_set_vol(&set_vol); - break; - } - case _IOC_NR(SNDRV_SST_GET_VOL): { - struct snd_sst_vol get_vol; - - if (copy_from_user(&get_vol, (void __user *)arg, - sizeof(get_vol))) { - retval = -EFAULT; - break; - } - pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n", - get_vol.stream_id); - if (minor == STREAM_MODULE && get_vol.stream_id == 0) { - pr_debug("invalid operation!\n"); - retval = -EPERM; - break; - } - retval = sst_get_vol(&get_vol); - if (retval) { - retval = -EIO; - break; - } - pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n", - get_vol.stream_id, get_vol.volume, - get_vol.ramp_duration, get_vol.ramp_type); - if (copy_to_user((struct snd_sst_vol __user *)arg, - &get_vol, sizeof(get_vol))) { - retval = -EFAULT; - break; - } - /*sst_print_get_vol_info(str_id, &get_vol);*/ - break; - } - - case _IOC_NR(SNDRV_SST_MUTE): { - struct snd_sst_mute set_mute; - - if (copy_from_user(&set_mute, (void __user *)arg, - sizeof(set_mute))) { - retval = -EFAULT; - break; - } - pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n", - set_mute.stream_id); - if (minor == STREAM_MODULE && set_mute.stream_id == 0) { - retval = -EPERM; - break; - } - retval = sst_set_mute(&set_mute); - break; - } - case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): { - struct snd_sst_get_stream_params get_params; - - pr_debug("IOCTL_GET_PARAMS received!\n"); - if (minor != 0) { - retval = -EBADRQC; - break; - } - - retval = sst_get_stream_params(str_id, &get_params); - if (retval) { - retval = -EIO; - break; - } - if (copy_to_user((struct snd_sst_get_stream_params __user *)arg, - &get_params, sizeof(get_params))) { - retval = -EFAULT; - break; - } - sst_print_stream_params(&get_params); - break; - } - - case _IOC_NR(SNDRV_SST_MMAP_PLAY): - case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): { - struct snd_sst_mmap_buffs mmap_buf; - - pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - if (copy_from_user(&mmap_buf, (void __user *)arg, - sizeof(mmap_buf))) { - retval = -EFAULT; - break; - } - retval = intel_sst_mmap_play_capture(str_id, &mmap_buf); - break; - } - case _IOC_NR(SNDRV_SST_STREAM_DROP): - pr_debug("SNDRV_SST_IOCTL_DROP received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_drop_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): { - struct snd_sst_tstamp tstamp = {0}; - unsigned long long time, freq, mod; - - pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - memcpy_fromio(&tstamp, - sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp), - sizeof(tstamp)); - time = tstamp.samples_rendered; - freq = (unsigned long long) tstamp.sampling_frequency; - time = time * 1000; /* converting it to ms */ - mod = do_div(time, freq); - if (copy_to_user((void __user *)arg, &time, - sizeof(unsigned long long))) - retval = -EFAULT; - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_START):{ - struct stream_info *stream; - - pr_debug("SNDRV_SST_STREAM_START received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_validate_strid(str_id); - if (retval) - break; - stream = &sst_drv_ctx->streams[str_id]; - mutex_lock(&stream->lock); - if (stream->status == STREAM_INIT && - stream->need_draining != true) { - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - if (stream->ops == STREAM_OPS_PLAYBACK || - stream->ops == STREAM_OPS_PLAYBACK_DRM) { - retval = sst_play_frame(str_id); - } else if (stream->ops == STREAM_OPS_CAPTURE) - retval = sst_capture_frame(str_id); - else { - retval = -EINVAL; - mutex_unlock(&stream->lock); - break; - } - if (retval < 0) { - stream->status = STREAM_INIT; - mutex_unlock(&stream->lock); - break; - } - } else { - retval = -EINVAL; - } - mutex_unlock(&stream->lock); - break; - } - - case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { - struct snd_sst_target_device target_device; - - pr_debug("SET_TARGET_DEVICE received!\n"); - if (copy_from_user(&target_device, (void __user *)arg, - sizeof(target_device))) { - retval = -EFAULT; - break; - } - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_target_device_select(&target_device); - break; - } - - case _IOC_NR(SNDRV_SST_DRIVER_INFO): { - struct snd_sst_driver_info info; - - pr_debug("SNDRV_SST_DRIVER_INFO received\n"); - info.version = SST_VERSION_NUM; - /* hard coding, shud get sumhow later */ - info.active_pcm_streams = sst_drv_ctx->stream_cnt - - sst_drv_ctx->encoded_cnt; - info.active_enc_streams = sst_drv_ctx->encoded_cnt; - info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM; - info.max_enc_streams = MAX_ENC_STREAM; - info.buf_per_stream = sst_drv_ctx->mmap_len; - if (copy_to_user((void __user *)arg, &info, - sizeof(info))) - retval = -EFAULT; - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_DECODE): { - struct snd_sst_dbufs param; - struct snd_sst_dbufs dbufs_local; - struct snd_sst_buffs ibufs, obufs; - struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp; - char __user *dest; - - pr_debug("SNDRV_SST_STREAM_DECODE received\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - if (copy_from_user(¶m, (void __user *)arg, - sizeof(param))) { - retval = -EFAULT; - break; - } - - dbufs_local.input_bytes_consumed = param.input_bytes_consumed; - dbufs_local.output_bytes_produced = - param.output_bytes_produced; - - if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) { - retval = -EFAULT; - break; - } - if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) { - retval = -EFAULT; - break; - } - - ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL); - obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL); - if (!ibuf_tmp || !obuf_tmp) { - retval = -ENOMEM; - goto free_iobufs; - } - - if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry, - ibufs.entries * sizeof(*ibuf_tmp))) { - retval = -EFAULT; - goto free_iobufs; - } - ibufs.buff_entry = ibuf_tmp; - dbufs_local.ibufs = &ibufs; - - if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry, - obufs.entries * sizeof(*obuf_tmp))) { - retval = -EFAULT; - goto free_iobufs; - } - obufs.buff_entry = obuf_tmp; - dbufs_local.obufs = &obufs; - - retval = sst_decode(str_id, &dbufs_local); - if (retval) { - retval = -EAGAIN; - goto free_iobufs; - } - - dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); - if (copy_to_user(dest, - &dbufs_local.input_bytes_consumed, - sizeof(unsigned long long))) { - retval = -EFAULT; - goto free_iobufs; - } - - dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); - if (copy_to_user(dest, - &dbufs_local.output_bytes_produced, - sizeof(unsigned long long))) { - retval = -EFAULT; - goto free_iobufs; - } -free_iobufs: - kfree(ibuf_tmp); - kfree(obuf_tmp); - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_DRAIN): - pr_debug("SNDRV_SST_STREAM_DRAIN received\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_drain_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): { - unsigned long long __user *bytes = (unsigned long long __user *)arg; - struct snd_sst_tstamp tstamp = {0}; - - pr_debug("STREAM_BYTES_DECODED received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - memcpy_fromio(&tstamp, - sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp), - sizeof(tstamp)); - if (copy_to_user(bytes, &tstamp.bytes_processed, - sizeof(*bytes))) - retval = -EFAULT; - break; - } - case _IOC_NR(SNDRV_SST_FW_INFO): { - struct snd_sst_fw_info *fw_info; - - pr_debug("SNDRV_SST_FW_INFO received\n"); - - fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC); - if (!fw_info) { - retval = -ENOMEM; - break; - } - retval = sst_get_fw_info(fw_info); - if (retval) { - retval = -EIO; - kfree(fw_info); - break; - } - if (copy_to_user((struct snd_sst_dbufs __user *)arg, - fw_info, sizeof(*fw_info))) { - kfree(fw_info); - retval = -EFAULT; - break; - } - /*sst_print_fw_info(fw_info);*/ - kfree(fw_info); - break; - } - case _IOC_NR(SNDRV_SST_GET_ALGO): - case _IOC_NR(SNDRV_SST_SET_ALGO): - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = intel_sst_ioctl_dsp(cmd, arg); - break; - - case _IOC_NR(SNDRV_SST_TUNING_PARAMS): - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_ioctl_tuning_params(arg); - break; - - default: - retval = -EINVAL; - } - pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval); - return retval; -} - |