/* * sst_get_stream_allocated - this function gets a stream allocated with * the given params * * @str_param : stream params * @lib_dnld : pointer to pointer of lib downlaod struct * * This creates new stream id for a stream, in case lib is to be downloaded to * DSP, it downloads that */ int sst_get_stream_allocated(struct snd_sst_params *str_param, struct snd_sst_lib_download **lib_dnld) { int retval, str_id; struct stream_info *str_info; retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops, str_param->codec, str_param->device_type); if (retval < 0) { pr_err("sst_alloc_stream failed %d\n", retval); return retval; } pr_debug("Stream allocated %d\n", retval); str_id = retval; str_info = &sst_drv_ctx->streams[str_id]; /* Block the call for reply */ retval = sst_wait_interruptible_timeout(sst_drv_ctx, &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) { pr_debug("FW alloc failed retval %d, ret_code %d\n", retval, str_info->ctrl_blk.ret_code); str_id = -str_info->ctrl_blk.ret_code; /*return error*/ *lib_dnld = str_info->ctrl_blk.data; sst_clean_stream(str_info); } else pr_debug("FW Stream allocated success\n"); return str_id; /*will ret either error (in above if) or correct str id*/ }
void free_stream_context(unsigned int str_id) { struct stream_info *stream; if (!sst_validate_strid(str_id)) { /* str_id is valid, so stream is alloacted */ stream = &sst_drv_ctx->streams[str_id]; if (sst_free_stream(str_id)) sst_clean_stream(&sst_drv_ctx->streams[str_id]); if (stream->ops == STREAM_OPS_PLAYBACK || stream->ops == STREAM_OPS_PLAYBACK_DRM) { sst_drv_ctx->pb_streams--; if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) sst_drv_ctx->scard_ops->power_down_pmic_pb( stream->device); else { if (sst_drv_ctx->pb_streams == 0) sst_drv_ctx->scard_ops-> power_down_pmic_pb(stream->device); } } else if (stream->ops == STREAM_OPS_CAPTURE) { sst_drv_ctx->cp_streams--; if (sst_drv_ctx->cp_streams == 0) sst_drv_ctx->scard_ops->power_down_pmic_cp( stream->device); } if (sst_drv_ctx->pb_streams == 0 && sst_drv_ctx->cp_streams == 0) sst_drv_ctx->scard_ops->power_down_pmic(); } }
/** * 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; struct intel_sst_ops *ops; unsigned long irq_flags; pr_debug("SST DBG:sst_resume_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; ops = sst_drv_ctx->ops; if (str_info->status == STREAM_RUNNING) return 0; if (str_info->status == STREAM_PAUSED) { if (str_info->ctrl_blk.on == true) { pr_err("SST ERR: control path in use\n"); return -EINVAL; } if (sst_create_short_msg(&msg)) { pr_err("SST ERR: 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; spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); ops->post_message(&sst_drv_ctx->ipc_post_msg_wq); retval = sst_wait_timeout(sst_drv_ctx, &str_info->ctrl_blk); if (!retval) { if (str_info->prev == STREAM_RUNNING) str_info->status = STREAM_RUNNING; else str_info->status = STREAM_INIT; str_info->prev = STREAM_PAUSED; } else if (retval == -SST_ERR_INVALID_STREAM_ID) { retval = -EINVAL; mutex_lock(&sst_drv_ctx->stream_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->stream_lock); } } else { retval = -EBADRQC; pr_err("SST ERR: BADQRC for stream\n"); } return retval; }
int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) { struct stream_info *stream; int ret = 0; stream = get_stream_info(ctx, str_id); if (stream) { /* str_id is valid, so stream is alloacted */ ret = sst_free_stream(ctx, str_id); if (ret) sst_clean_stream(&ctx->streams[str_id]); return ret; } else { dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id); } return ret; }
/** * 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(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; struct stream_info *str_info; struct intel_sst_ops *ops; dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); mutex_lock(&sst_drv_ctx->sst_lock); if (sst_drv_ctx->sst_state == SST_RESET) { mutex_unlock(&sst_drv_ctx->sst_lock); return -ENODEV; } mutex_unlock(&sst_drv_ctx->sst_lock); str_info = get_stream_info(sst_drv_ctx, str_id); if (!str_info) return -EINVAL; ops = sst_drv_ctx->ops; mutex_lock(&str_info->lock); if (str_info->status != STREAM_UN_INIT) { str_info->prev = str_info->status; str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", str_id, str_info->pipe_id); retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, NULL, NULL, true, true, false, true); dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", retval); mutex_lock(&sst_drv_ctx->sst_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->sst_lock); dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); } else { mutex_unlock(&str_info->lock); retval = -EBADRQC; dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); } 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(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; struct stream_info *str_info; dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); str_info = get_stream_info(sst_drv_ctx, str_id); if (!str_info) return -EINVAL; if (str_info->status == STREAM_RUNNING) return 0; if (str_info->status == STREAM_PAUSED) { retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, str_info->pipe_id, 0, NULL, NULL, true, true, false, true); if (!retval) { if (str_info->prev == STREAM_RUNNING) str_info->status = STREAM_RUNNING; else str_info->status = STREAM_INIT; str_info->prev = STREAM_PAUSED; } else if (retval == -SST_ERR_INVALID_STREAM_ID) { retval = -EINVAL; mutex_lock(&sst_drv_ctx->sst_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->sst_lock); } } else { retval = -EBADRQC; dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); } 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; struct intel_sst_ops *ops; unsigned long irq_flags; pr_debug("SST DBG:sst_free_stream for %d\n", str_id); mutex_lock(&sst_drv_ctx->sst_lock); if (sst_drv_ctx->sst_state == SST_UN_INIT) { mutex_unlock(&sst_drv_ctx->sst_lock); return -ENODEV; } mutex_unlock(&sst_drv_ctx->sst_lock); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; ops = sst_drv_ctx->ops; mutex_lock(&str_info->lock); if (str_info->status != STREAM_UN_INIT) { str_info->prev = str_info->status; str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); if (str_info->ctrl_blk.on == true) { pr_err("SST ERR: control path in use\n"); return -EINVAL; } if (sst_create_short_msg(&msg)) { pr_err("SST ERR: mem allocation failed\n"); return -ENOMEM; } if (sst_drv_ctx->pci_id == SST_MRFLD_PCI_ID) sst_fill_header_mrfld(&msg->mrfld_header, IPC_IA_FREE_STREAM, 0, str_id); else sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id); spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 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); } str_info->ctrl_blk.on = true; str_info->ctrl_blk.condition = false; ops->post_message(&sst_drv_ctx->ipc_post_msg_wq); retval = sst_wait_timeout(sst_drv_ctx, &str_info->ctrl_blk); pr_debug("sst: wait for free returned %d\n", retval); mutex_lock(&sst_drv_ctx->stream_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->stream_lock); pr_debug("SST DBG:Stream freed\n"); } else { mutex_unlock(&str_info->lock); retval = -EBADRQC; pr_debug("SST DBG:BADQRC for stream\n"); } 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; unsigned int pvt_id; struct ipc_post *msg = NULL; struct stream_info *str_info; struct intel_sst_ops *ops; unsigned long irq_flags; struct ipc_dsp_hdr dsp_hdr; struct sst_block *block; pr_debug("SST DBG:sst_free_stream for %d\n", str_id); mutex_lock(&sst_drv_ctx->sst_lock); if (sst_drv_ctx->sst_state == SST_UN_INIT) { mutex_unlock(&sst_drv_ctx->sst_lock); return -ENODEV; } mutex_unlock(&sst_drv_ctx->sst_lock); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; ops = sst_drv_ctx->ops; mutex_lock(&str_info->lock); if (str_info->status != STREAM_UN_INIT) { str_info->prev = str_info->status; str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); if (!sst_drv_ctx->use_32bit_ops) { pvt_id = sst_assign_pvt_id(sst_drv_ctx); retval = sst_create_block_and_ipc_msg(&msg, true, sst_drv_ctx, &block, IPC_CMD, pvt_id); if (retval) return retval; sst_fill_header_mrfld(&msg->mrfld_header, IPC_CMD, str_info->task_id, 1, pvt_id); msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr); sst_fill_header_dsp(&dsp_hdr, IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0); memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); } else { retval = sst_create_block_and_ipc_msg(&msg, false, sst_drv_ctx, &block, IPC_IA_FREE_STREAM, str_id); if (retval) return retval; sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id); } spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); if (!sst_drv_ctx->use_32bit_ops) { /*FIXME: do we need to wake up drain stream here, * how to get the pvt_id and msg_id */ } else { sst_wake_up_block(sst_drv_ctx, 0, str_id, IPC_IA_DRAIN_STREAM, NULL, 0); } ops->post_message(&sst_drv_ctx->ipc_post_msg_wq); retval = sst_wait_timeout(sst_drv_ctx, block); pr_debug("sst: wait for free returned %d\n", retval); mutex_lock(&sst_drv_ctx->stream_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->stream_lock); pr_debug("SST DBG:Stream freed\n"); sst_free_block(sst_drv_ctx, block); } else { mutex_unlock(&str_info->lock); retval = -EBADRQC; pr_debug("SST DBG:BADQRC for stream\n"); } 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; struct intel_sst_ops *ops; unsigned long irq_flags; struct sst_block *block = NULL; int pvt_id, len; struct ipc_dsp_hdr dsp_hdr; pr_debug("SST DBG:sst_resume_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; ops = sst_drv_ctx->ops; if (str_info->status == STREAM_RUNNING) return 0; if (str_info->status == STREAM_PAUSED) { if (!sst_drv_ctx->use_32bit_ops) { pvt_id = sst_assign_pvt_id(sst_drv_ctx); retval = sst_create_block_and_ipc_msg(&msg, true, sst_drv_ctx, &block, IPC_CMD, pvt_id); if (retval) return retval; sst_fill_header_mrfld(&msg->mrfld_header, IPC_CMD, str_info->task_id, 1, pvt_id); msg->mrfld_header.p.header_high.part.res_rqd = 1; len = sizeof(dsp_hdr); msg->mrfld_header.p.header_low_payload = len; sst_fill_header_dsp(&dsp_hdr, IPC_IA_RESUME_STREAM_MRFLD, str_info->pipe_id, 0); memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); } else { retval = sst_create_block_and_ipc_msg(&msg, false, sst_drv_ctx, &block, IPC_IA_RESUME_STREAM, str_id); if (retval) return retval; sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id); } spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); ops->post_message(&sst_drv_ctx->ipc_post_msg_wq); retval = sst_wait_timeout(sst_drv_ctx, block); sst_free_block(sst_drv_ctx, block); if (!retval) { if (str_info->prev == STREAM_RUNNING) str_info->status = STREAM_RUNNING; else str_info->status = STREAM_INIT; str_info->prev = STREAM_PAUSED; } else if (retval == -SST_ERR_INVALID_STREAM_ID) { retval = -EINVAL; mutex_lock(&sst_drv_ctx->stream_lock); sst_clean_stream(str_info); mutex_unlock(&sst_drv_ctx->stream_lock); } } else { retval = -EBADRQC; pr_err("SST ERR: BADQRC for stream\n"); } return retval; }