diff options
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch | 1690 |
1 files changed, 0 insertions, 1690 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch deleted file mode 100644 index 888b6a084..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-5-8.patch +++ /dev/null @@ -1,1690 +0,0 @@ -From 174aae2c1dcb1b7c49188e13167c21687ef96edc Mon Sep 17 00:00:00 2001 -From: R, Dharageswari <dharageswari.r@intel.com> -Date: Thu, 29 Apr 2010 20:26:02 +0530 -Subject: [PATCH] ADR-Post-Beta-0.05.002.03-5/8-Moorestown Audio Drivers: SST stream ops module - -This adds the stream module which contains the function for stream -operations & control. For a stream the control and data are two major parts. -This module implements the control (play/pause/resume/stop/free/alloc) -for a stream. It also implements data play/capture frames where buffers are -sent/received to FW. The objective of SST driver is to achieve Low power -playback by utilizing DSP as much aspossible. So SST gets large music -buffers from player/middleware and sends them to FW in a scatter gather list. -The FW decodes and renders them, while IA can goto low power states - -Signed-off-by: Vinod Koul <vinod.koul@intel.com> - - new file: sound/pci/sst/intel_sst_stream.c -Patch-mainline: 2.6.35? ---- - sound/pci/sst/intel_sst_stream.c | 1658 ++++++++++++++++++++++++++++++++++++++ - 1 files changed, 1658 insertions(+), 0 deletions(-) - create mode 100644 sound/pci/sst/intel_sst_stream.c - -diff --git a/sound/pci/sst/intel_sst_stream.c b/sound/pci/sst/intel_sst_stream.c -new file mode 100644 -index 0000000..07a4e55 ---- /dev/null -+++ b/sound/pci/sst/intel_sst_stream.c -@@ -0,0 +1,1658 @@ -+/* -+ * intel_sst_stream.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> -+ * KP Jeeja <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 file contains the stream operations of SST driver -+ */ -+ -+#include <linux/cdev.h> -+#include <linux/pci.h> -+#include <linux/kernel.h> -+#include <linux/syscalls.h> -+#include <linux/file.h> -+#include <linux/interrupt.h> -+#include <linux/list.h> -+#include <linux/uaccess.h> -+#include <linux/firmware.h> -+#ifdef CONFIG_MSTWN_POWER_MGMT -+#include <linux/intel_mid.h> -+#endif -+#include <linux/rar/rar_register.h> -+#include <linux/rar/memrar.h> -+#include <sound/intel_sst_ioctl.h> -+#include <sound/intel_lpe.h> -+#include "intel_sst_fw_ipc.h" -+#include "intel_sst_common.h" -+/** -+* sst_alloc_stream - Send msg for a new stream ID -+* @params: stream params -+* @stream_ops: operation of stream PB/capture -+* @codec: codec for stream -+* @session_id: pvt_id passed by MMF to distinguish stream -+* -+* This function is called by any function which wants to start -+* a new stream. This also check if a stream exists which is idle -+* it initializes idle stream id to this request -+*/ -+int sst_alloc_stream(char *params, unsigned int stream_ops, -+ u8 codec, unsigned int session_id) -+{ -+ struct ipc_post *msg = NULL; -+ struct snd_sst_alloc_params alloc_param = {{0,},}; -+ -+ printk(KERN_DEBUG "SST DBG:entering sst_alloc_stream \n"); -+ printk(KERN_DEBUG "SST DBG:%d %d %d\n", stream_ops, codec, session_id); -+ -+ BUG_ON(!params); -+ -+ /* send msg to FW to allocate a stream */ -+ if (sst_create_large_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, IPC_IA_ALLOC_STREAM, 1, 0); -+ msg->header.part.data = sizeof(alloc_param) + sizeof(u32); -+ alloc_param.str_type.codec_type = codec; -+ alloc_param.str_type.str_type = STREAM_TYPE_MUSIC; /* music */ -+ alloc_param.str_type.operation = stream_ops; -+ alloc_param.str_type.protected_str = 0; /* non drm */ -+ alloc_param.str_type.pvt_id = session_id; -+ memcpy(&alloc_param.stream_params, params, -+ sizeof(struct snd_sst_stream_params)); -+ -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), &alloc_param, -+ sizeof(alloc_param)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ printk(KERN_DEBUG "SST DBG:alloc stream done\n"); -+ return 0; -+} -+ -+/** -+* sst_get_stream_params - Send msg to query for stream parameters -+* @str_id: stream id for which the parameters are queried for -+* @get_params: out parameters to which the parameters are copied to -+* -+* This function is called when the stream parameters are queiried for -+*/ -+int sst_get_stream_params(int str_id, -+ struct snd_sst_get_stream_params *get_params) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ struct snd_sst_fw_get_stream_params *fw_params; -+ -+ printk(KERN_DEBUG "SST DBG:get_stream for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ -+ str_info = &sst_drv_ctx->streams[str_id]; -+ if (str_info->status != STREAM_UN_INIT) { -+ if (str_info->ctrl_blk.on == true) { -+ printk(KERN_ERR\ -+ "SST ERR: control path is already in use \n"); -+ return -EINVAL; -+ } -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR -+ "SST ERR: message creation failed\n"); -+ return -ENOMEM; -+ } -+ fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC); -+ if (!fw_params) { -+ printk(KERN_ERR -+ "SST ERR: mem allcoation failed\n "); -+ return -ENOMEM; -+ } -+ -+ sst_fill_header(&msg->header, IPC_IA_GET_STREAM_PARAMS, -+ 0, str_id); -+ str_info->ctrl_blk.condition = false; -+ str_info->ctrl_blk.ret_code = 0; -+ str_info->ctrl_blk.on = true; -+ str_info->ctrl_blk.data = (void *) fw_params; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); -+ if (retval) { -+ get_params->codec_params.result = retval; -+ kfree(fw_params); -+ return -EIO; -+ } -+ memcpy(&get_params->pcm_params, &fw_params->pcm_params, -+ sizeof(fw_params->pcm_params)); -+ memcpy(&get_params->codec_params.sparams, -+ &fw_params->codec_params, -+ sizeof(fw_params->codec_params)); -+ get_params->codec_params.result = 0; -+ get_params->codec_params.stream_id = str_id; -+ get_params->codec_params.codec = str_info->codec; -+ get_params->codec_params.ops = str_info->ops; -+ get_params->codec_params.stream_type = str_info->str_type; -+ kfree(fw_params); -+ } else { -+ printk(KERN_DEBUG "SST DBG:Stream is not in the init state\n"); -+ } -+ return retval; -+} -+ -+/** -+* sst_get_fw_info - Send msg to query for firmware configurations -+* @info: out param that holds the firmare configurations -+* -+* This function is called when the firmware configurations are queiried for -+*/ -+int sst_get_fw_info(struct snd_sst_fw_info *info) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ -+ printk(KERN_DEBUG "SST DBG:...called \n"); -+ -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR -+ "SST ERR: message creation failed\n"); -+ return -ENOMEM; -+ } -+ -+ sst_fill_header(&msg->header, IPC_IA_GET_FW_INFO, 0, 0); -+ sst_drv_ctx->fw_info_blk.condition = false; -+ sst_drv_ctx->fw_info_blk.ret_code = 0; -+ sst_drv_ctx->fw_info_blk.on = true; -+ sst_drv_ctx->fw_info_blk.data = info; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->fw_info_blk, SST_BLOCK_TIMEOUT); -+ if (retval) { -+ printk(KERN_ERR \ -+ "SST ERR: error in fw_info = %d\n", retval); -+ retval = -EIO; -+ } -+ return retval; -+} -+ -+ -+/** -+* sst_alloc_stream_response - process alloc reply -+* @str_id: stream id for which the stream has been allocated -+* @type the stream parameters that are allocated -+ -+* This function is called by firmware as a response to stream allcoation -+* request -+*/ -+int sst_alloc_stream_response(unsigned int str_id, -+ struct snd_sst_str_type *type) -+{ -+ int retval = 0, i, valid_str = 0; -+ struct ipc_post *msg = NULL; -+ -+ /* allocation succesfull */ -+ printk(KERN_DEBUG "SST DBG:stream number given = %d \n", str_id); -+ -+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) { -+ if (type->pvt_id == sst_drv_ctx->alloc_block[i].sst_id) { -+ valid_str = 1; -+ break; -+ } -+ } -+ if (!valid_str) { -+ /* this is not valid stream */ -+ printk(KERN_ERR \ -+ "SST ERR: Invalid stream allocation detetcted... freeing\n"); -+ if (sst_create_short_msg(&msg)) -+ return -ENOMEM; -+ sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ return 0; -+ } -+ -+ sst_init_stream(&sst_drv_ctx->streams[str_id], type->codec_type, -+ type->str_type, type->pvt_id, type->operation); -+ -+ printk(KERN_DEBUG "SST DBG:stream pvt id = %d \n", type->pvt_id); -+ -+ /* Unblock with retval code */ -+ sst_wake_up_alloc_block(sst_drv_ctx, type->pvt_id, str_id, NULL); -+ return retval; -+} -+ -+/** -+* sst_pause_stream - Send msg for a pausing stream -+* @str_id: stream ID -+* -+* This function is called by any function which wants to pause -+* an already running stream. -+*/ -+int sst_pause_stream(int str_id) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ -+ printk(KERN_DEBUG "SST DBG:sst_pause_stream for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ str_info = &sst_drv_ctx->streams[str_id]; -+ if (str_info->status == STREAM_PAUSED) -+ return 0; -+ if (str_info->status == STREAM_RUNNING || -+ str_info->status == STREAM_INIT) { -+ if (str_info->prev == STREAM_UN_INIT) -+ return -EBADRQC; -+ if (str_info->ctrl_blk.on == true) { -+ printk(KERN_ERR \ -+ "SST ERR: control path is already in use\n "); -+ return -EINVAL; -+ } -+ if (sst_create_short_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, IPC_IA_PAUSE_STREAM, 0, str_id); -+ str_info->ctrl_blk.condition = false; -+ str_info->ctrl_blk.ret_code = 0; -+ str_info->ctrl_blk.on = true; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, -+ &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); -+ if (retval == 0) { -+ str_info->prev = str_info->status; -+ str_info->status = STREAM_PAUSED; -+ /*sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);*/ -+ } else if (retval == SST_ERR_INVALID_STREAM_ID) { -+ retval = -EINVAL; -+ sst_clean_stream(str_info); -+ } -+ } else { -+ retval = -EBADRQC; -+ printk(KERN_ERR "SST ERR: +\ -+ BADQRC for stream\n "); -+ } -+ -+ return retval; -+} -+int sst_enable_rx_timeslot(int status) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR \ -+ "SST ERR: short message mem +\ -+ allocation failed\n"); -+ return -ENOMEM; -+ } -+ printk(KERN_DEBUG "SST DBG:ipc message sending:: **********SST_ENABLE_RX_TIME_SLOT*********** \n"); -+ sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0); -+ msg->header.part.data = status; -+ sst_drv_ctx->hs_info_blk.condition = false; -+ sst_drv_ctx->hs_info_blk.ret_code = 0; -+ sst_drv_ctx->hs_info_blk.on = true; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, -+ &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT); -+ return retval; -+} -+ -+/** -+* sst_resume_stream - Send msg for resuming stream -+* @str_id: stream ID -+* -+* This function is called by any function which wants to resume -+* an already paused stream. -+*/ -+int sst_resume_stream(int str_id) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ -+ printk(KERN_DEBUG "SST DBG:sst_resume_stream for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ str_info = &sst_drv_ctx->streams[str_id]; -+ if (str_info->status == STREAM_RUNNING) -+ return 0; -+ if (str_info->status == STREAM_PAUSED) { -+ if (str_info->ctrl_blk.on == true) { -+ printk(KERN_ERR \ -+ "SST ERR: control path is already in use\n"); -+ return -EINVAL; -+ } -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR \ -+ "SST ERR: short message mem +\ -+ allocation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id); -+ str_info->ctrl_blk.condition = false; -+ str_info->ctrl_blk.ret_code = 0; -+ str_info->ctrl_blk.on = true; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, -+ &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); -+ if (!retval) { -+ if (str_info->prev == STREAM_RUNNING) -+ str_info->status = STREAM_RUNNING; -+ else -+ str_info->status = STREAM_INIT; -+ str_info->prev = STREAM_PAUSED; -+ /*sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY);*/ -+ } else if (retval == -SST_ERR_INVALID_STREAM_ID) { -+ retval = -EINVAL; -+ sst_clean_stream(str_info); -+ } -+ } else { -+ retval = -EBADRQC; -+ printk(KERN_ERR "SST ERR: BADQRC for stream\n"); -+ } -+ -+ return retval; -+} -+ -+ -+/** -+* sst_drop_stream - Send msg for stopping stream -+* @str_id: stream ID -+* -+* This function is called by any function which wants to stop -+* a stream. -+*/ -+int sst_drop_stream(int str_id) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct sst_stream_bufs *bufs = NULL, *_bufs; -+ struct stream_info *str_info; -+ -+ printk(KERN_DEBUG "SST DBG:sst_drop_stream for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ str_info = &sst_drv_ctx->streams[str_id]; -+ -+ if (str_info->status != STREAM_UN_INIT && -+ str_info->status != STREAM_DECODE) { -+ if (str_info->ctrl_blk.on == true) { -+ printk(KERN_ERR \ -+ "SST ERR: control path is already in use\n"); -+ return -EINVAL; -+ } -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR \ -+ "SST ERR: short message mem +\ -+ allocation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_DROP_STREAM, 0, str_id); -+ str_info->ctrl_blk.condition = false; -+ str_info->ctrl_blk.ret_code = 0; -+ str_info->ctrl_blk.on = true; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, -+ &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); -+ if (!retval) { -+ printk(KERN_DEBUG "SST DBG:drop success\n"); -+ str_info->prev = STREAM_UN_INIT; -+ str_info->status = STREAM_INIT; -+ if (str_info->src != MAD_DRV) { -+ mutex_lock(&str_info->lock); -+ list_for_each_entry_safe(bufs, _bufs, -+ &str_info->bufs, node) { -+ list_del(&bufs->node); -+ kfree(bufs); -+ } -+ mutex_unlock(&str_info->lock); -+ } -+ str_info->cumm_bytes += str_info->curr_bytes; -+ /*sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);*/ -+ } else if (retval == -SST_ERR_INVALID_STREAM_ID) { -+ retval = -EINVAL; -+ sst_clean_stream(str_info); -+ } -+ if (str_info->data_blk.on == true) { -+ str_info->data_blk.condition = true; -+ str_info->data_blk.ret_code = retval; -+ wake_up(&sst_drv_ctx->wait_queue); -+ } -+ } else { -+ retval = -EBADRQC; -+ printk(KERN_ERR "SST ERR:BADQRC for stream\n"); -+ } -+ return retval; -+} -+ -+/** -+* sst_drain_stream - Send msg for draining stream -+* @str_id: stream ID -+* -+* This function is called by any function which wants to drain -+* a stream. -+*/ -+int sst_drain_stream(int str_id) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ -+ printk(KERN_DEBUG "SST DBG:sst_drain_stream for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ str_info = &sst_drv_ctx->streams[str_id]; -+ -+ if (str_info->status != STREAM_RUNNING && -+ str_info->status != STREAM_INIT && -+ str_info->status != STREAM_PAUSED) { -+ printk(KERN_ERR \ -+ "SST ERR: BADQRC for stream = %d\n", str_info->status); -+ return -EBADRQC; -+ } -+ -+ if (str_info->status == STREAM_INIT) { -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR\ -+ "SST ERR: short message mem +\ -+ allocation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, 0, str_id); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ } else -+ str_info->need_draining = true; -+ str_info->data_blk.condition = false; -+ str_info->data_blk.ret_code = 0; -+ str_info->data_blk.on = true; -+ retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk); -+ str_info->need_draining = false; -+ if (retval == -SST_ERR_INVALID_STREAM_ID) { -+ retval = -EINVAL; -+ sst_clean_stream(str_info); -+ } -+ return retval; -+} -+ -+/** -+* sst_free_stream - Frees a stream -+* @str_id: stream ID -+* -+* This function is called by any function which wants to free -+* a stream. -+*/ -+int sst_free_stream(int str_id) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ -+ printk(KERN_DEBUG "SST DBG:sst_free_stream for %d\n", str_id); -+ -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ str_info = &sst_drv_ctx->streams[str_id]; -+ -+ if (str_info->status != STREAM_UN_INIT) { -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR \ -+ "SST ERR: short message mem +\ -+ allocation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ str_info->prev = str_info->status; -+ str_info->status = STREAM_UN_INIT; -+ if (str_info->data_blk.on == true) { -+ str_info->data_blk.condition = true; -+ str_info->data_blk.ret_code = 0; -+ wake_up(&sst_drv_ctx->wait_queue); -+ } -+ sst_clean_stream(str_info); -+ printk(KERN_DEBUG "SST DBG:Stream freed\n"); -+ /*sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);*/ -+ -+ } else { -+ retval = -EBADRQC; -+ printk(KERN_DEBUG "SST DBG:BADQRC for stream\n"); -+ } -+ -+ return retval; -+} -+ -+ -+/** -+* sst_set_stream_param - Send msg for setting stream parameters -+* @id: stream id -+* @params: stream params -+* -+* This function sets stream params during runtime -+*/ -+int sst_set_stream_param(int str_id, struct snd_sst_params *str_param) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct stream_info *str_info; -+ -+ BUG_ON(!str_param); -+ if(sst_drv_ctx->streams[str_id].ops != str_param->ops) { -+ printk(KERN_ERR "SST ERR: Invalid operation\n"); -+ return -EINVAL; -+ } -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ printk(KERN_DEBUG "SST DBG:set_stream for %d\n", str_id); -+ str_info = &sst_drv_ctx->streams[str_id]; -+ if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) { -+ if (str_info->ctrl_blk.on == true) { -+ printk(KERN_ERR \ -+ "SST ERR: control path is already in use\n"); -+ return -EINVAL; -+ } -+ if (sst_create_large_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, -+ IPC_IA_SET_STREAM_PARAMS, 1, str_id); -+ str_info->ctrl_blk.condition = false; -+ str_info->ctrl_blk.ret_code = 0; -+ str_info->ctrl_blk.on = true; -+ msg->header.part.data = sizeof(u32) + -+ sizeof(str_param->sparams); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), &str_param->sparams, -+ sizeof(str_param->sparams)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); -+ if (retval < 0) { -+ retval = -EIO; -+ sst_clean_stream(str_info); -+ } -+ } else { -+ retval = -EBADRQC; -+ printk(KERN_ERR "SST ERR: BADQRC for stream\n"); -+ } -+ return retval; -+} -+ -+/** -+* sst_get_vol - This fuction allows to get the premix gain or gain of a stream -+* @get_vol: this is an output param through which the volume -+* structure is passed back to user -+* -+* This function is called when the premix gain or stream gain is queried for -+*/ -+int sst_get_vol(struct snd_sst_vol *get_vol) -+{ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ struct snd_sst_vol *fw_get_vol; -+ int str_id = get_vol->stream_id; -+ -+ printk(KERN_DEBUG "SST DBG:get vol called \n"); -+ -+ if (sst_create_short_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, -+ IPC_IA_GET_STREAM_VOL, 0, str_id); -+ sst_drv_ctx->vol_info_blk.condition = false; -+ sst_drv_ctx->vol_info_blk.ret_code = 0; -+ sst_drv_ctx->vol_info_blk.on = true; -+ fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC); -+ if (!fw_get_vol) { -+ printk(KERN_ERR "SST ERR: mem +\ -+ allcoation failed\n"); -+ return -ENOMEM; -+ } -+ sst_drv_ctx->vol_info_blk.data = (void *)fw_get_vol; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); -+ if (retval) -+ retval = -EIO; -+ else { -+ printk(KERN_DEBUG "SST DBG:stream +\ -+ id = %d\n", fw_get_vol->stream_id); -+ printk(KERN_DEBUG "SST DBG:+\ -+ volume = %d\n", fw_get_vol->volume); -+ printk(KERN_DEBUG "SST DBG:ramp +\ -+ dur = %d\n", fw_get_vol->ramp_duration); -+ printk(KERN_DEBUG "SST DBG:ramp_type +\ -+ = %d\n", fw_get_vol->ramp_type); -+ memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol)); -+ } -+ return retval; -+} -+ -+/** -+* sst_set_vol - This fuction allows to set the premix gain or gain of a stream -+* @set_vol: this holds the volume structure that needs to be set -+* -+* This function is called when premix gain or stream gain is requested to be set -+*/ -+int sst_set_vol(struct snd_sst_vol *set_vol) -+{ -+ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ -+ printk(KERN_DEBUG "SST DBG:set vol called \n"); -+ -+ if (sst_create_large_msg(&msg)) { -+ printk(KERN_ERR "SST ERR:+\ -+ message creation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1, -+ set_vol->stream_id); -+ -+ msg->header.part.data = sizeof(u32) + sizeof(*set_vol); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), set_vol, sizeof(*set_vol)); -+ sst_drv_ctx->vol_info_blk.condition = false; -+ sst_drv_ctx->vol_info_blk.ret_code = 0; -+ sst_drv_ctx->vol_info_blk.on = true; -+ sst_drv_ctx->vol_info_blk.data = set_vol; -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); -+ if (retval) { -+ printk(KERN_ERR \ -+ "SST ERR: error in set_vol = %d\n", retval); -+ retval = -EIO; -+ } -+ return retval; -+} -+ -+/** -+* sst_get_vol - This fuction allows to set premix mute or soft mute of a stream -+* @set_mute: this holds the mute structure that needs to be set -+* -+* This function is called when premix mute or stream mute is requested to be set -+*/ -+int sst_set_mute(struct snd_sst_mute *set_mute) -+{ -+ -+ int retval = 0; -+ struct ipc_post *msg = NULL; -+ -+ printk(KERN_DEBUG "SST DBG:set mute called \n"); -+ -+ if (sst_create_large_msg(&msg)) { -+ printk(KERN_ERR "SST ERR: +\ -+ message creation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1, -+ set_mute->stream_id); -+ sst_drv_ctx->mute_info_blk.condition = false; -+ sst_drv_ctx->mute_info_blk.ret_code = 0; -+ sst_drv_ctx->mute_info_blk.on = true; -+ sst_drv_ctx->mute_info_blk.data = set_mute; -+ -+ msg->header.part.data = sizeof(u32) + sizeof(*set_mute); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), set_mute, -+ sizeof(*set_mute)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT); -+ if (retval) { -+ printk(KERN_ERR\ -+ "SST ERR: error in set_mute +\ -+ = %d\n", retval); -+ retval = -EIO; -+ } -+ return retval; -+} -+ -+int sst_parse_target(struct snd_sst_slot_info *slot) -+{ -+ -+ if (slot->device_type == SND_SST_DEVICE_PCM) { -+ /*pcm device, check params*/ -+ if(slot->device_instance == 1) { -+ if ((slot->device_mode != SND_SST_DEV_MODE_PCM_MODE4_I2S) -+ && (slot->device_mode != SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED)) -+ goto err; -+ } else if(slot->device_instance == 0) { -+ if (slot->device_mode != SND_SST_DEV_MODE_PCM_MODE2) -+ goto err; -+ if (slot->pcm_params.sfreq != 8000 || -+ slot->pcm_params.num_chan != 1 || -+ slot->pcm_params.pcm_wd_sz != 16) -+ goto err; -+ -+ } else { -+ err: -+ dev_err(&sst_drv_ctx->pci->dev, "SST ERR: i/p params incorrect\n"); -+ return -EINVAL; -+ } -+ } -+ /*params ok, now process*/ -+ if (slot->target_type == SND_SST_TARGET_PMIC && -+ slot->device_instance == 1) { -+ sst_drv_ctx->pmic_port_instance = 1; -+ sst_drv_ctx->scard_ops->set_audio_port(ACTIVATE); -+ sst_drv_ctx->scard_ops->set_voice_port(DEACTIVATE); -+ sst_drv_ctx->scard_ops->set_pcm_audio_params( -+ slot->pcm_params.sfreq, -+ slot->pcm_params.pcm_wd_sz, -+ slot->pcm_params.num_chan); -+ if (sst_drv_ctx->pb_streams ) -+ sst_drv_ctx->scard_ops->power_up_pmic_pb(1); -+ if (sst_drv_ctx->cp_streams) -+ sst_drv_ctx->scard_ops->power_up_pmic_cp(1); -+ } else if ((slot->target_type == SND_SST_TARGET_PMIC || -+ slot->target_type == SND_SST_TARGET_OTHER) && -+ slot->device_instance == 0) { -+ sst_drv_ctx->pmic_port_instance = 0; -+ sst_drv_ctx->scard_ops->set_audio_port(DEACTIVATE); -+ sst_drv_ctx->scard_ops->set_voice_port(ACTIVATE); -+ if (sst_drv_ctx->pb_streams ) -+ sst_drv_ctx->scard_ops->power_up_pmic_pb(0); -+ if (sst_drv_ctx->cp_streams) -+ sst_drv_ctx->scard_ops->power_up_pmic_cp(0); -+ } -+ return 0; -+} -+ -+int sst_send_target(struct snd_sst_target_device *target) -+{ -+ int retval; -+ struct ipc_post *msg; -+ -+ if (sst_create_large_msg(&msg)) { -+ dev_err(&sst_drv_ctx->pci->dev, "SST ERR: message creation failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0); -+ sst_drv_ctx->tgt_dev_blk.condition = false; -+ sst_drv_ctx->tgt_dev_blk.ret_code = 0; -+ sst_drv_ctx->tgt_dev_blk.on = true; -+ -+ msg->header.part.data = sizeof(u32) + sizeof(*target); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), target, -+ sizeof(*target)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ printk(KERN_DEBUG "SST DBG:message sent- waiting\n"); -+ retval = sst_wait_interruptible_timeout(sst_drv_ctx, -+ &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT); -+ if (retval) -+ dev_err(&sst_drv_ctx->pci->dev, "SST ERR: +\ -+ target device ipc failed = 0x%x\n", retval); -+ return retval; -+ -+} -+/** -+* sst_target_device_select - This fuction sets the target device configurations -+* @target_device: this parameter holds the configurations to be set -+* -+* This function is called when the user layer wants to change the target -+* device's configurations -+*/ -+ -+int sst_target_device_select(struct snd_sst_target_device *target) -+{ -+ int retval, i; -+ -+ printk(KERN_DEBUG "SST DBG:Target Device Select\n"); -+ -+ if (target->device_route < 0 || target->device_route > 2) { -+ dev_err(&sst_drv_ctx->pci->dev, "SST ERR: device route is invalid\n"); -+ return -EINVAL; -+ } -+ -+ if (target->device_route != 0) { -+ dev_err(&sst_drv_ctx->pci->dev, "SST ERR: Unsupported config\n"); -+ return -EIO; -+ } -+ for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { -+ if (target->devices[i].action == SND_SST_PORT_ACTIVATE) { -+ printk(KERN_DEBUG "SST DBG:activate called in %d\n", i); -+ retval = sst_parse_target(&target->devices[i]); -+ if (retval) -+ return retval; -+ } else if (target->devices[i].action == SND_SST_PORT_PREPARE) -+ printk(KERN_DEBUG "SST DBG:PREPARE in %d, FWding\n", i); -+ } -+ return sst_send_target(target); -+} -+ -+/** -+* This function gets the physical address of the secure memory from the handle -+*/ -+static inline int sst_get_RAR(struct RAR_buffer *buffers, int count) -+{ -+ int retval = 0, rar_status = 0; -+ -+ rar_status = rar_handle_to_bus(buffers, count); -+ -+ if (count != rar_status) { -+ printk(KERN_ERR "SST ERR: The rar CALL Failed"); -+ retval = -EIO; -+ } -+ if (buffers->info.type != RAR_TYPE_AUDIO) { -+ printk(KERN_ERR "SST ERR:Invalid RAR type\n"); -+ return -EINVAL; -+ } -+ return retval; -+} -+ -+/** -+* This function creates the scatter gather list to be sent to firmware to -+* capture/playback data -+*/ -+static int sst_create_sg_list(struct stream_info *stream, -+ struct sst_frame_info *sg_list) -+{ -+ struct sst_stream_bufs *kbufs = NULL; -+ struct RAR_buffer rar_buffers; -+ int retval = 0; -+ int i = 0; -+ -+ list_for_each_entry(kbufs, &stream->bufs, node) { -+ if (kbufs->in_use == false) { -+ if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { -+ printk(KERN_DEBUG "DRM playback handling \n"); -+ rar_buffers.info.handle = (__u32)kbufs->addr; -+ rar_buffers.info.size = kbufs->size; -+ printk(KERN_DEBUG "rar handle = 0x%x size=0x%x", rar_buffers.info.handle, rar_buffers.info.size); -+ retval = sst_get_RAR(&rar_buffers, 1); -+ -+ if (retval) -+ return retval; -+ sg_list->addr[i].addr = rar_buffers.bus_address; -+ sg_list->addr[i].size = (__u32)kbufs->size; /* rar_buffers.info.size; */ -+ printk(KERN_DEBUG "SST DBG:phy addr[%d] 0x%x +\ -+ Size 0x%x\n", i, sg_list->addr[i].addr,\ -+ sg_list->addr[i].size); -+ } else { -+ sg_list->addr[i].addr = -+ virt_to_phys((void *) -+ kbufs->addr + kbufs->offset); -+ sg_list->addr[i].size = kbufs->size; -+ printk(KERN_DEBUG "SST DBG:phy addr[%d] 0x%x +\ -+ Size 0x%x\n", i,\ -+ sg_list->addr[i].addr,\ -+ kbufs->size); -+ } -+ stream->curr_bytes += sg_list->addr[i].size; -+ kbufs->in_use = true; -+ i++; -+ } -+ if (i >= MAX_NUM_SCATTER_BUFFERS) -+ break; -+ } -+ -+ sg_list->num_entries = i; -+ printk(KERN_DEBUG "SST DBG:sg list entries +\ -+ = %d \n", sg_list->num_entries); -+ return i; -+} -+ -+/** -+* sst_play_frame - Send msg for sending stream frames -+* @str_id: ID of stream -+* -+* This function is called to send data to be played out -+* to the firmware -+*/ -+int sst_play_frame(int str_id) -+{ -+ int i = 0, retval = 0; -+ struct ipc_post *msg = NULL; -+ struct sst_frame_info sg_list = {0}; -+ struct sst_stream_bufs *kbufs = NULL, *_kbufs; -+ struct stream_info *stream; -+ -+ printk(KERN_DEBUG "SST DBG:play frame for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ -+ stream = &sst_drv_ctx->streams[str_id]; -+ /* clear prev sent buffers */ -+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { -+ if (kbufs->in_use == true) { -+ if ((!stream->period_elapsed) && !(in_interrupt()) ){ -+ spin_lock(&stream->pcm_lock); -+ list_del(&kbufs->node); -+ kfree(kbufs); -+ printk(KERN_DEBUG "SST DBG:del node \n"); -+ spin_unlock(&stream->pcm_lock); -+ } -+ else { -+ list_del(&kbufs->node); -+ kfree(kbufs); -+ printk(KERN_DEBUG "SST DBG:del node \n"); -+ } -+ } -+ } -+ /* update bytes sent */ -+ stream->cumm_bytes += stream->curr_bytes; -+ stream->curr_bytes = 0; -+ if (list_empty(&stream->bufs)) { -+ /* no user buffer available */ -+ printk(KERN_DEBUG "SST DBG:Null buffer!!!!stream +\ -+ status = %d \n", stream->status); -+ stream->prev = stream->status; -+ stream->status = STREAM_INIT; -+ printk(KERN_DEBUG "SST DBG:new stream status +\ -+ = %d \n", stream->status); -+ if (stream->need_draining == true) { -+ printk(KERN_DEBUG "SST DBG:draining stream \n"); -+ if (sst_create_short_msg(&msg)) { -+ printk(KERN_ERR \ -+ "SST ERR: short message mem +\ -+ alloc failed\n"); -+ return -ENOMEM; -+ } -+ sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, -+ 0, str_id); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, -+ &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ } else if (stream->data_blk.on == true) { -+ printk(KERN_DEBUG "SST DBG:user list is empty.. wake \n"); -+ /* unblock */ -+ stream->data_blk.ret_code = 0; -+ stream->data_blk.condition = true; -+ stream->data_blk.on = false; -+ wake_up(&sst_drv_ctx->wait_queue); -+ } -+#ifdef CONFIG_MSTWN_POWER_MGMT -+ sst_ospm_send_event(OSPM_EVENT_AUDIO_BUF_EMPTY); -+#endif -+ return 0; -+ } -+ -+ /* create list */ -+ i = sst_create_sg_list(stream, &sg_list); -+ -+ /* post msg */ -+ if (sst_create_large_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, IPC_IA_PLAY_FRAMES, 1, str_id); -+ msg->header.part.data = sizeof(u32) + sizeof(sg_list); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ return 0; -+ -+} -+ -+/** -+* sst_capture_frame - Send msg for sending stream frames -+* @str_id: ID of stream -+* -+* This function is called to capture data from the firmware -+*/ -+int sst_capture_frame(int str_id) -+{ -+ int i = 0, retval = 0; -+ struct ipc_post *msg = NULL; -+ struct sst_frame_info sg_list = {0}; -+ struct sst_stream_bufs *kbufs = NULL, *_kbufs; -+ struct stream_info *stream; -+ -+ -+ printk(KERN_DEBUG "SST DBG:capture frame for %d\n", str_id); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ stream = &sst_drv_ctx->streams[str_id]; -+ /*update bytes sent*/ -+ /*stream->cumm_bytes += stream->curr_bytes; -+ stream->curr_bytes = 0;*/ -+ /* clear prev sent buffers */ -+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { -+ if (kbufs->in_use == true) { -+ list_del(&kbufs->node); -+ kfree(kbufs); -+ printk(KERN_DEBUG "SST DBG:del node \n"); -+ } -+ } -+ if (list_empty(&stream->bufs)) { -+ /* no user buffer available */ -+ printk(KERN_DEBUG "SST DBG:Null buffer!!!!stream +\ -+ status = %d \n", stream->status); -+ stream->prev = stream->status; -+ stream->status = STREAM_INIT; -+ printk(KERN_DEBUG "SST DBG:new stream +\ -+ status = %d \n", stream->status); -+ if (stream->data_blk.on == true) { -+ printk(KERN_DEBUG "SST DBG:user list is empty.. wake \n"); -+ /* unblock */ -+ stream->data_blk.ret_code = 0; -+ stream->data_blk.condition = true; -+ stream->data_blk.on = false; -+ wake_up(&sst_drv_ctx->wait_queue); -+ -+ } -+#ifdef CONFIG_MSTWN_POWER_MGMT -+ sst_ospm_send_event(OSPM_EVENT_AUDIO_BUF_FULL); -+#endif -+ return 0; -+ } -+ -+ /* create new sg list */ -+ i = sst_create_sg_list(stream, &sg_list); -+ -+ /* post msg */ -+ if (sst_create_large_msg(&msg)) -+ return -ENOMEM; -+ -+ sst_fill_header(&msg->header, IPC_IA_CAPT_FRAMES, 1, str_id); -+ msg->header.part.data = sizeof(u32) + sizeof(sg_list); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ -+ -+ /*update bytes recevied*/ -+ stream->cumm_bytes += stream->curr_bytes; -+ stream->curr_bytes = 0; -+ -+ printk(KERN_DEBUG "SST DBG:Cum bytes = %d \n", stream->cumm_bytes); -+ return 0; -+} -+ -+/** -+* This function is used to calculate the minimum size of input buffers given -+*/ -+static unsigned int calculate_min_size(struct snd_sst_buffs *bufs) -+{ -+ int i, min_val = bufs->buff_entry[0].size; -+ for (i = 1 ; i < bufs->entries; i++) { -+ if (bufs->buff_entry[i].size < min_val) -+ min_val = bufs->buff_entry[i].size; -+ } -+ printk(KERN_DEBUG "SST DBG:min_val = %d\n", min_val); -+ return min_val; -+} -+ -+/** -+* This function is used to calculate the maximum size of input buffers given -+*/ -+static unsigned int calculate_max_size(struct snd_sst_buffs *bufs) -+{ -+ int i, max_val = bufs->buff_entry[0].size; -+ for (i = 1 ; i < bufs->entries; i++) { -+ if (bufs->buff_entry[i].size > max_val) -+ max_val = bufs->buff_entry[i].size; -+ } -+ printk(KERN_DEBUG "SST DBG:max_val = %d\n", max_val); -+ return max_val; -+} -+ -+/** -+* This function is used to allocate input and output buffers to be sent to -+* the firmware that will take encoded data and return decoded data -+*/ -+static int sst_allocate_decode_buf(struct stream_info *str_info, -+ struct snd_sst_dbufs *dbufs, -+ unsigned int cum_input_given, -+ unsigned int cum_output_given) -+{ -+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { -+ -+ if (dbufs->ibufs->type == SST_BUF_RAR && dbufs->obufs->type == SST_BUF_RAR ) { -+ if (dbufs->ibufs->entries == dbufs->obufs->entries) -+ return 0; -+ else { -+ printk(KERN_ERR "SST ERR: +\ -+ RAR buffer entries do not match \n"); -+ return -EINVAL; -+ } -+ } -+ else -+ str_info->decode_osize = cum_output_given; -+ return 0; -+ -+ } -+ if (!str_info->decode_ibuf) { -+ printk(KERN_DEBUG "SST DBG:no input buffers, trying full size\n"); -+ str_info->decode_isize = cum_input_given; -+ str_info->decode_ibuf = kzalloc(str_info->decode_isize, -+ GFP_KERNEL); -+ str_info->idecode_alloc = str_info->decode_isize; -+ } -+ if (!str_info->decode_ibuf) { -+ printk(KERN_DEBUG "SST DBG:buff alloaction failed, trying max size\n"); -+ str_info->decode_isize = calculate_max_size(dbufs->ibufs); -+ str_info->decode_ibuf = kzalloc(str_info->decode_isize, -+ GFP_KERNEL); -+ str_info->idecode_alloc = str_info->decode_isize; -+ } -+ if (!str_info->decode_ibuf) { -+ printk(KERN_DEBUG "SST DBG:buff alloaction failed, trying min size\n"); -+ str_info->decode_isize = calculate_min_size(dbufs->ibufs); -+ str_info->decode_ibuf = kzalloc(str_info->decode_isize, -+ GFP_KERNEL); -+ if (!str_info->decode_ibuf) { -+ printk(KERN_ERR \ -+ "SST ERR: mem allocation failed\n"); -+ return -ENOMEM; -+ } -+ str_info->idecode_alloc = str_info->decode_isize; -+ } -+ str_info->decode_osize = cum_output_given; -+ if (str_info->decode_osize > sst_drv_ctx->mmap_len) -+ str_info->decode_osize = sst_drv_ctx->mmap_len; -+ return 0; -+} -+ -+/** -+* This function is used to send the message to firmware to decode the data -+*/ -+static int sst_send_decode_mess(int str_id, struct stream_info *str_info, -+ struct snd_sst_decode_info *dec_info) -+{ -+ struct ipc_post *msg = NULL; -+ int retval = 0; -+ -+ printk(KERN_DEBUG "SST DBG:called \n"); -+ -+ if ( str_info->decode_ibuf_type == SST_BUF_RAR ) { -+ dec_info->frames_in.addr[0].addr = (unsigned long) str_info->decode_ibuf; -+ dec_info->frames_in.addr[0].size = str_info->decode_isize; -+ -+ } else { -+ dec_info->frames_in.addr[0].addr = virt_to_phys((void *) -+ str_info->decode_ibuf); -+ dec_info->frames_in.addr[0].size = str_info->decode_isize; -+ } -+ -+ -+ if ( str_info->decode_obuf_type == SST_BUF_RAR ) { -+ dec_info->frames_out.addr[0].addr = (unsigned long) str_info->decode_obuf; -+ dec_info->frames_out.addr[0].size = str_info->decode_osize; -+ -+ } else { -+ dec_info->frames_out.addr[0].addr = virt_to_phys((void *) -+ str_info->decode_obuf ) ; -+ dec_info->frames_out.addr[0].size = str_info->decode_osize; -+ } -+ -+ dec_info->frames_in.num_entries = 1; -+ dec_info->frames_out.num_entries = 1; -+ dec_info->frames_in.rsrvd = 0; -+ dec_info->frames_out.rsrvd = 0; -+ dec_info->input_bytes_consumed = 0; -+ dec_info->output_bytes_produced = 0; -+ if (sst_create_large_msg(&msg)) { -+ printk(KERN_ERR "SST ERR: message +\ -+ creation failed\n"); -+ return -ENOMEM; -+ } -+ -+ sst_fill_header(&msg->header, IPC_IA_DECODE_FRAMES, 1, str_id); -+ msg->header.part.data = sizeof(u32) + sizeof(*dec_info); -+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); -+ memcpy(msg->mailbox_data + sizeof(u32), dec_info, -+ sizeof(*dec_info)); -+ mutex_lock(&sst_drv_ctx->list_lock); -+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); -+ mutex_unlock(&sst_drv_ctx->list_lock); -+ str_info->data_blk.condition = false; -+ str_info->data_blk.ret_code = 0; -+ str_info->data_blk.on = true; -+ str_info->data_blk.data = dec_info; -+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); -+ retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk); -+ return retval; -+} -+ -+/** -+* This function is used to prepare the kernel input buffers with contents before -+* sendind for decode -+*/ -+static int sst_prepare_input_buffers(struct stream_info *str_info, -+ struct snd_sst_dbufs *dbufs, -+ int *input_index, int *in_copied, int *input_index_valid_size, int *new_entry_flag) -+{ -+ int i, cpy_size, retval = 0; -+ -+ printk(KERN_DEBUG "SST DBG:input_index = %d, +\ -+ input entries = %d\n", *input_index, -+ dbufs->ibufs->entries); -+ for (i = *input_index; i < dbufs->ibufs->entries; i++) { -+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { -+ struct RAR_buffer rar_buffers; -+ __u32 info; -+ retval = copy_from_user((void *) &info, -+ dbufs->ibufs->buff_entry[i].buffer, -+ sizeof(__u32)); -+ if (retval) { -+ printk(KERN_ERR "SST ERR:copy from user failed\n"); -+ return -EAGAIN; -+ } -+ rar_buffers.info.type = dbufs->ibufs->type; -+ rar_buffers.info.size = dbufs->ibufs->buff_entry[i].size; -+ rar_buffers.info.handle = info; -+ printk(KERN_DEBUG "rar handle in DnR(input buffer function)=0x%x size=0x%x" \ -+ , rar_buffers.info.handle, rar_buffers.info.size); -+ retval = sst_get_RAR(&rar_buffers, 1); -+ if (retval) { -+ printk(KERN_ERR "SST ERR: RAR API failed\n"); -+ return retval; -+ } -+ str_info->decode_ibuf = (void *) ((unsigned long) rar_buffers.bus_address); -+ printk(KERN_DEBUG "RAR buffer address in DnR (input buffer function):: +\ -+ 0x%lu", (unsigned long) str_info->decode_ibuf); -+ printk(KERN_DEBUG "rar handle in DnR decode funtion/output b_add rar +\ -+ = 0x%lu", (unsigned long) rar_buffers.bus_address); -+ -+ *input_index = i + 1; -+ -+ str_info->decode_isize = dbufs->ibufs->buff_entry[i].size; -+ str_info->decode_ibuf_type = dbufs->ibufs->type; -+ *in_copied = str_info->decode_isize; -+ printk(KERN_DEBUG "rar address in input prepare= 0x%lu size=0x%x +\ -+ incopied Size =%d ", (unsigned long) str_info->decode_ibuf, +\ -+ str_info->decode_isize ,*in_copied); -+ break; -+ } -+ *input_index = i; -+ if (*input_index_valid_size == 0) -+ *input_index_valid_size = dbufs->ibufs->buff_entry[i].size; -+ printk(KERN_DEBUG "SST DBG:inout addr = %p, size = %d\n", -+ dbufs->ibufs->buff_entry[i].buffer, -+ *input_index_valid_size); -+ printk(KERN_DEBUG "SST DBG:decode_isize = %d, in_copied = %d\n", -+ str_info->decode_isize, *in_copied); -+ if (*input_index_valid_size <= -+ (str_info->decode_isize - *in_copied)) -+ cpy_size = *input_index_valid_size; -+ else -+ cpy_size = str_info->decode_isize - *in_copied; -+ -+ printk(KERN_DEBUG "SST DBG:cpy size = %d\n", cpy_size); -+ if (!dbufs->ibufs->buff_entry[i].buffer) { -+ printk(KERN_ERR "SST ERR: +\ -+ input buffer is null\n"); -+ return -EINVAL; -+ } -+ printk(KERN_DEBUG "SST DBG:Trying copy To: %p, From %p, size %d\n", -+ str_info->decode_ibuf + *in_copied, -+ dbufs->ibufs->buff_entry[i].buffer, cpy_size); -+ -+ retval = -+ copy_from_user((void *)(str_info->decode_ibuf + *in_copied), -+ (void *) dbufs->ibufs->buff_entry[i].buffer, -+ cpy_size); -+ if (retval) { -+ printk(KERN_ERR\ -+ "SST ERR: copy from user failed \n"); -+ return -EIO; -+ } -+ *in_copied += cpy_size; -+ *input_index_valid_size -= cpy_size; -+ printk(KERN_DEBUG "SST DBG:in buff size = %d, in_copied = %d\n", -+ *input_index_valid_size, *in_copied); -+ if (*input_index_valid_size != 0) { -+ printk(KERN_DEBUG "SST DBG:more input buffers left \n"); -+ dbufs->ibufs->buff_entry[i].buffer += -+ cpy_size; -+ break; -+ } -+ if (*in_copied == str_info->decode_isize && -+ *input_index_valid_size == 0 && (i+1) <= dbufs->ibufs->entries) { -+ printk(KERN_DEBUG "SST DBG:all input buffers copied\n"); -+ *new_entry_flag = true; -+ *input_index = i + 1; -+ break; -+ } -+ } -+ return retval; -+} -+ -+/** -+* This function is used to copy the decoded data from kernel buffers to -+* the user output buffers with contents after decode -+*/ -+static int sst_prepare_output_buffers(struct stream_info *str_info, -+ struct snd_sst_dbufs *dbufs, -+ int *output_index, int output_size, -+ int *out_copied) -+ -+{ -+ int i, cpy_size, retval = 0; -+ printk(KERN_DEBUG "SST DBG:output_index = %d, output entries = %d\n", -+ *output_index, -+ dbufs->obufs->entries); -+ for (i = *output_index; i < dbufs->obufs->entries; i++) { -+ *output_index = i; -+ printk(KERN_DEBUG "SST DBG:output addr = %p, size = %d\n", -+ dbufs->obufs->buff_entry[i].buffer, -+ dbufs->obufs->buff_entry[i].size); -+ printk(KERN_DEBUG "SST DBG:output_size = %d, out_copied = %d\n", -+ output_size, *out_copied); -+ if (dbufs->obufs->buff_entry[i].size < -+ (output_size - *out_copied)) -+ cpy_size = dbufs->obufs->buff_entry[i].size; -+ else -+ cpy_size = output_size - *out_copied; -+ printk(KERN_DEBUG "SST DBG:cpy size = %d\n", cpy_size); -+ printk(KERN_DEBUG "SST DBG:Trying copy To: %p, From %p, size %d\n", -+ dbufs->obufs->buff_entry[i].buffer, -+ sst_drv_ctx->mmap_mem + *out_copied, -+ cpy_size); -+ retval = copy_to_user(dbufs->obufs->buff_entry[i].buffer, -+ sst_drv_ctx->mmap_mem + *out_copied, -+ cpy_size); -+ if (retval) { -+ printk(KERN_ERR "SST ERR: +\ -+ copy to user failed \n"); -+ return -EIO; -+ } else -+ printk(KERN_DEBUG "SST DBG:copy to user passed \n"); -+ *out_copied += cpy_size; -+ dbufs->obufs->buff_entry[i].size -= cpy_size; -+ printk(KERN_DEBUG "SST DBG:output buff size = %d, out_copied = %d\n", -+ dbufs->obufs->buff_entry[i].size, *out_copied); -+ if (dbufs->obufs->buff_entry[i].size != 0) { -+ *output_index = i; -+ dbufs->obufs->buff_entry[i].buffer += cpy_size; -+ break; -+ } else if (*out_copied == output_size) { -+ *output_index = i + 1; -+ break; -+ } -+ } -+ return retval; -+} -+ -+/** -+* sst_decode - Send msg for decoding frames -+* @str_id: ID of stream -+* @dbufs - param that holds the user input and output buffers and sizes -+* This function is called to decode data from the firmware -+*/ -+int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) -+{ -+ int retval = 0, i; -+ unsigned long long total_input = 0 , total_output = 0; -+ unsigned int cum_input_given = 0 , cum_output_given = 0; -+ int copy_in_done = false, copy_out_done = false; -+ int input_index = 0, output_index = 0; -+ int input_index_valid_size = 0; -+ int in_copied, out_copied; -+ int new_entry_flag; -+ u64 output_size; -+ struct stream_info *str_info; -+ struct snd_sst_decode_info dec_info; -+ -+ printk(KERN_DEBUG "SST DBG:...called \n"); -+ sst_drv_ctx->scard_ops->power_down_pmic(); -+ printk(KERN_DEBUG "SST DBG: Powering_down_PMIC.... \n"); -+ retval = sst_validate_strid(str_id); -+ if (retval) -+ return retval; -+ -+ str_info = &sst_drv_ctx->streams[str_id]; -+ if (str_info->status != STREAM_INIT) { -+ printk(KERN_ERR "SST ERR: invalid +\ -+ stream state = %d\n", str_info->status); -+ return -EINVAL; -+ } -+ -+ str_info->prev = str_info->status; -+ str_info->status = STREAM_DECODE; -+ for (i = 0; i < dbufs->ibufs->entries; i++) -+ cum_input_given += dbufs->ibufs->buff_entry[i].size; -+ for (i = 0; i < dbufs->obufs->entries; i++) -+ cum_output_given += dbufs->obufs->buff_entry[i].size; -+ /* input and output buffer allocation */ -+ retval = sst_allocate_decode_buf(str_info, dbufs, -+ cum_input_given, cum_output_given); -+ str_info->decode_isize = str_info->idecode_alloc; -+ if (retval) { -+ printk(KERN_ERR "SST ERR: +\ -+ mem allocation failed, abort!!!\n"); -+ retval = -ENOMEM; -+ goto finish; -+ } -+ -+ str_info->decode_ibuf_type = dbufs->ibufs->type; -+ str_info->decode_obuf_type = dbufs->obufs->type; -+ -+ while ((copy_out_done == false) && (copy_in_done == false)) { -+ in_copied = 0; -+ new_entry_flag = false; -+ retval = sst_prepare_input_buffers(str_info,\ -+ dbufs, &input_index, &in_copied, &input_index_valid_size, &new_entry_flag); -+ printk(KERN_DEBUG "SST DBG:prep inbuf ret %d\n", retval); -+ if (retval) { -+ printk(KERN_ERR \ -+ "SST ERR: prepare in buffers failed\n"); -+ goto finish; -+ } -+ -+ printk(KERN_DEBUG "rar handle output buffer type = 0x%x ", dbufs->obufs->type); -+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) -+ str_info->decode_obuf = sst_drv_ctx->mmap_mem; -+ else { -+ -+ if( dbufs->obufs->type == SST_BUF_RAR ) { -+ struct RAR_buffer rar_buffers; -+ __u32 info; -+ retval = copy_from_user((void *) &info, -+ dbufs->obufs->buff_entry[output_index].buffer, -+ sizeof(__u32)); -+ -+ rar_buffers.info.size = dbufs->obufs->buff_entry[output_index].size; -+ rar_buffers.info.handle = info; -+ printk(KERN_DEBUG "rar handle in DnR(decode funtion)= 0x%x size=0x%x",\ -+ rar_buffers.info.handle, rar_buffers.info.size); -+ retval = sst_get_RAR(&rar_buffers, 1); -+ if (retval) -+ return retval; -+ -+ -+ str_info->decode_obuf = (void *) ((unsigned long)rar_buffers.bus_address); -+ str_info->decode_osize = dbufs->obufs->buff_entry[output_index].size; -+ str_info->decode_obuf_type = dbufs->obufs->type; -+ printk(KERN_DEBUG "SST DBG:DRM handling\n"); -+ printk(KERN_DEBUG "rar handle in DnR decode funtion/output b_add = 0x%lu +\ -+ output Size=0x%x", (unsigned long) str_info->decode_obuf ,\ -+ str_info->decode_osize); -+ } -+ else -+ { -+ str_info->decode_obuf = sst_drv_ctx->mmap_mem; -+ str_info->decode_osize = dbufs->obufs->buff_entry[output_index].size; -+ -+ } -+ } -+ -+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { -+ if (str_info->decode_isize > in_copied) { -+ str_info->decode_isize = in_copied; -+ printk(KERN_DEBUG "SST DBG:input size modified = %d\n", -+ str_info->decode_isize); -+ } -+ } -+ -+ -+ retval = sst_send_decode_mess(str_id, str_info, &dec_info); -+ if (retval) { -+ printk(KERN_ERR \ -+ "SST ERR: sending message failed\n"); -+ goto finish; -+ } -+ printk(KERN_DEBUG "SST DBG:in_copied = %d, consumed = %lld, produced = %lld\n", -+ in_copied, -+ dec_info.input_bytes_consumed, -+ dec_info.output_bytes_produced); -+ if (dbufs->obufs->type == SST_BUF_RAR) { -+ output_index += 1; -+ if (output_index == dbufs->obufs->entries) { -+ copy_in_done = true; -+ printk(KERN_DEBUG "SST DBG:all input copy done\n"); -+ } -+ total_output += dec_info.output_bytes_produced; -+ } else { -+ out_copied = 0; -+ output_size = dec_info.output_bytes_produced; -+ retval = sst_prepare_output_buffers(str_info, dbufs, -+ &output_index, output_size, &out_copied); -+ if (retval) { -+ printk(KERN_ERR \ -+ "SST ERR: prepare out +\ -+ buffers failed\n"); -+ goto finish; -+ } -+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { -+ if (in_copied != dec_info.input_bytes_consumed) { -+ int bytes_left = in_copied - dec_info.input_bytes_consumed; -+ printk(KERN_DEBUG "SST DBG:input left to be copied = %d \n", -+ bytes_left); -+ if(new_entry_flag == true) { -+ input_index--; -+ } -+ while (bytes_left) { -+ unsigned int size_sent = dbufs->ibufs->buff_entry[input_index].size - input_index_valid_size; -+ if (bytes_left == size_sent) { -+ bytes_left = 0; -+ } else if (bytes_left < size_sent) { -+ dbufs->ibufs->buff_entry[input_index].buffer += (size_sent - bytes_left); -+ dbufs->ibufs->buff_entry[input_index].size -= (size_sent - bytes_left); -+ bytes_left = 0; -+ } else { -+ bytes_left -= size_sent; -+ input_index--; -+ input_index_valid_size = 0; -+ } -+ } -+ -+ } -+ } -+ -+ total_output += out_copied; -+ if (str_info->decode_osize != out_copied) { -+ str_info->decode_osize -= out_copied; -+ printk(KERN_DEBUG "SST DBG:output size modified = %d\n", -+ str_info->decode_osize); -+ } -+ } -+ total_input += dec_info.input_bytes_consumed; -+ -+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { -+ if (total_input == cum_input_given) -+ copy_in_done = true; -+ copy_out_done = true; -+ -+ } else { -+ if (total_output == cum_output_given) { -+ copy_out_done = true; -+ printk(KERN_DEBUG "SST DBG:all output copy done\n"); -+ } -+ -+ if (total_input == cum_input_given) { -+ copy_in_done = true; -+ printk(KERN_DEBUG "SST DBG:all input copy done\n"); -+ } -+ } -+ -+ printk(KERN_DEBUG "SST DBG:copy_out_done = %d, copy_in_done = %d \n", -+ copy_out_done, copy_in_done); -+ } -+ -+finish: -+ dbufs->input_bytes_consumed = total_input; -+ dbufs->output_bytes_produced = total_output; -+ str_info->status = str_info->prev; -+ str_info->prev = STREAM_DECODE; -+ str_info->decode_ibuf = NULL; -+ kfree(str_info->decode_ibuf); -+ -+ return retval; -+} --- -1.6.2.2 - |