static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, struct snd_compr_tstamp *tstamp) { struct snd_sst_tstamp fw_tstamp = {0,}; struct stream_info *stream; struct intel_sst_drv *ctx = dev_get_drvdata(dev); memcpy_fromio(&fw_tstamp, ((void *)(ctx->mailbox + ctx->tstamp) +(str_id * sizeof(fw_tstamp))), sizeof(fw_tstamp)); stream = get_stream_info(ctx, str_id); if (!stream) return -EINVAL; dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter); tstamp->copied_total = fw_tstamp.ring_buffer_counter; tstamp->pcm_frames = fw_tstamp.frames_decoded; tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24))); tstamp->sampling_rate = fw_tstamp.sampling_frequency; dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n", str_id, tstamp->copied_total, tstamp->pcm_frames); dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames); return 0; }
/** * 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(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_drop_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_UN_INIT) { str_info->prev = STREAM_UN_INIT; str_info->status = STREAM_INIT; str_info->cumm_bytes = 0; retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, str_info->pipe_id, 0, NULL, NULL, true, true, true, false); } else { retval = -EBADRQC; dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", str_info->status); } return retval; }
/* * sst_close_pcm_stream - Close PCM interface * * @str_id: stream id to be closed * * This function is called by MID sound card driver to close * an existing pcm interface */ static int sst_close_pcm_stream(struct device *dev, unsigned int str_id) { struct stream_info *stream; int retval = 0; struct intel_sst_drv *ctx = dev_get_drvdata(dev); stream = get_stream_info(ctx, str_id); if (!stream) { dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id); return -EINVAL; } if (stream->status == STREAM_RESET) { /* silently fail here as we have cleaned the stream earlier */ dev_dbg(ctx->dev, "stream in reset state...\n"); retval = 0; goto put; } retval = free_stream_context(ctx, str_id); put: stream->pcm_substream = NULL; stream->status = STREAM_UN_INIT; stream->period_elapsed = NULL; ctx->stream_cnt--; if (retval) dev_err(ctx->dev, "free stream returned err %d\n", retval); dev_dbg(ctx->dev, "Exit\n"); return 0; }
/** * 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(struct intel_sst_drv *sst_drv_ctx, int str_id, bool partial_drain) { int retval = 0; struct stream_info *str_info; dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_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 && str_info->status != STREAM_INIT && str_info->status != STREAM_PAUSED) { dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", str_info->status); return -EBADRQC; } retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, sizeof(u8), &partial_drain, NULL, true, true, false, false); /* * with new non blocked drain implementation in core we dont need to * wait for respsonse, and need to only invoke callback for drain * complete */ return retval; }
static int sst_cdev_close(struct device *dev, unsigned int str_id) { int retval; struct stream_info *stream; struct intel_sst_drv *ctx = dev_get_drvdata(dev); stream = get_stream_info(ctx, str_id); if (!stream) { dev_err(dev, "stream info is NULL for str %d!!!\n", str_id); return -EINVAL; } if (stream->status == STREAM_RESET) { dev_dbg(dev, "stream in reset state...\n"); stream->status = STREAM_UN_INIT; retval = 0; goto put; } retval = sst_free_stream(ctx, str_id); put: stream->compr_cb_param = NULL; stream->compr_cb = NULL; if (retval) dev_err(dev, "free stream returned err %d\n", retval); dev_dbg(dev, "End\n"); return retval; }
static int sst_cdev_ack(struct device *dev, unsigned int str_id, unsigned long bytes) { struct stream_info *stream; struct snd_sst_tstamp fw_tstamp = {0,}; int offset; void __iomem *addr; struct intel_sst_drv *ctx = dev_get_drvdata(dev); stream = get_stream_info(ctx, str_id); if (!stream) return -EINVAL; /* update bytes sent */ stream->cumm_bytes += bytes; dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes); memcpy_fromio(&fw_tstamp, ((void *)(ctx->mailbox + ctx->tstamp) +(str_id * sizeof(fw_tstamp))), sizeof(fw_tstamp)); fw_tstamp.bytes_copied = stream->cumm_bytes; dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n", fw_tstamp.bytes_copied, bytes); addr = ((void *)(ctx->mailbox + ctx->tstamp)) + (str_id * sizeof(fw_tstamp)); offset = offsetof(struct snd_sst_tstamp, bytes_copied); sst_shim_write(addr, offset, fw_tstamp.bytes_copied); return 0; }
static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) { int str_id = 0; struct stream_info *stream; struct intel_sst_drv *ctx = dev_get_drvdata(dev); str_id = str_info->str_id; if (ctx->sst_state != SST_FW_RUNNING) return 0; stream = get_stream_info(ctx, str_id); if (!stream) return -EINVAL; dev_dbg(ctx->dev, "setting the period ptrs\n"); stream->pcm_substream = str_info->arg; stream->period_elapsed = str_info->period_elapsed; stream->sfreq = str_info->sfreq; stream->prev = stream->status; stream->status = STREAM_INIT; dev_dbg(ctx->dev, "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n", stream->pcm_substream, stream->period_elapsed, stream->sfreq, stream->status); return 0; }
/** * 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, bool partial_drain) { int retval = 0, pvt_id, len; struct ipc_post *msg = NULL; struct stream_info *str_info; struct intel_sst_ops *ops; unsigned long irq_flags; struct sst_block *block = NULL; struct ipc_dsp_hdr dsp_hdr; pr_debug("SST DBG:sst_drain_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 && str_info->status != STREAM_INIT && str_info->status != STREAM_PAUSED) { pr_err("SST ERR: BADQRC for stream = %d\n", str_info->status); return -EBADRQC; } 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); pr_debug("header:%x\n", (unsigned int)msg->mrfld_header.p.header_high.full); msg->mrfld_header.p.header_high.part.res_rqd = 1; len = sizeof(u8) + sizeof(dsp_hdr); msg->mrfld_header.p.header_low_payload = len; sst_fill_header_dsp(&dsp_hdr, IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, sizeof(u8)); memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); memcpy(msg->mailbox_data + sizeof(dsp_hdr), &partial_drain, sizeof(u8)); } else { retval = sst_create_block_and_ipc_msg(&msg, false, sst_drv_ctx, &block, IPC_IA_DRAIN_STREAM, str_id); if (retval) return retval; sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, 0, str_id); msg->header.part.data = partial_drain; } 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_interruptible(sst_drv_ctx, block); sst_free_block(sst_drv_ctx, block); return retval; }
static int sst_cdev_stream_start(struct device *dev, unsigned int str_id) { struct stream_info *str_info; struct intel_sst_drv *ctx = dev_get_drvdata(dev); str_info = get_stream_info(ctx, str_id); if (!str_info) return -EINVAL; str_info->prev = str_info->status; str_info->status = STREAM_RUNNING; return sst_start_stream(ctx, str_id); }
/** * 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; }
static int sst_stream_drop(struct device *dev, int str_id) { struct stream_info *str_info; struct intel_sst_drv *ctx = dev_get_drvdata(dev); if (ctx->sst_state != SST_FW_RUNNING) return 0; str_info = get_stream_info(ctx, str_id); if (!str_info) return -EINVAL; str_info->prev = STREAM_UN_INIT; str_info->status = STREAM_INIT; return sst_drop_stream(ctx, str_id); }
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; }
static int fdk_aac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt) { FDKAACDecContext *s = avctx->priv_data; AVFrame *frame = data; int ret; AAC_DECODER_ERROR err; UINT valid = avpkt->size; err = aacDecoder_Fill(s->handle, &avpkt->data, &avpkt->size, &valid); if (err != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "aacDecoder_Fill() failed: %x\n", err); return AVERROR_INVALIDDATA; } err = aacDecoder_DecodeFrame(s->handle, (INT_PCM *) s->decoder_buffer, s->decoder_buffer_size / sizeof(INT_PCM), 0); if (err == AAC_DEC_NOT_ENOUGH_BITS) { ret = avpkt->size - valid; goto end; } if (err != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "aacDecoder_DecodeFrame() failed: %x\n", err); ret = AVERROR_UNKNOWN; goto end; } if ((ret = get_stream_info(avctx)) < 0) goto end; frame->nb_samples = avctx->frame_size; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) goto end; memcpy(frame->extended_data[0], s->decoder_buffer, avctx->channels * avctx->frame_size * av_get_bytes_per_sample(avctx->sample_fmt)); *got_frame_ptr = 1; ret = avpkt->size - valid; end: return ret; }
/** * sst_start_stream - Send msg for a starting stream * @str_id: stream ID * * This function is called by any function which wants to start * a stream. */ int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; struct stream_info *str_info; u16 data = 0; dev_dbg(sst_drv_ctx->dev, "sst_start_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 -EBADRQC; retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, sizeof(u16), &data, NULL, true, true, true, false); return retval; }
int fdk_aac_decode_frame(AAC_Dec codec, INT_PCM *output_buf, int *output_size, int *got_frame) { AAC_DECODER_ERROR err; int ret; UINT valid = codec->in_buffer_size; err = aacDecoder_Fill(codec->handle, codec->in_buffer, &codec->in_buffer_size, &valid); if(err != AAC_DEC_OK){ LOGI("aacDecoder_Fill() failed: 0x%x", err); return err; } if(codec->initialized){ } err = aacDecoder_DecodeFrame(codec->handle, output_buf, codec->pcm_pkt_size, codec->flags); if (err == AAC_DEC_NOT_ENOUGH_BITS) { ret = codec->in_buffer_size - valid; goto end; } if(err != AAC_DEC_OK){ LOGI("aacDecoder_DecodeFrame() failed: 0x%x", err); ret = AAC_DEC_DECODE_FRAME_ERROR; goto end; } if(!codec->initialized) { ret = get_stream_info(codec); if(ret != 0) { LOGI("get_stream_info failed"); goto end; } codec->initialized = 1; } *got_frame = 1; *output_size = codec->pcm_pkt_size; return (codec->in_buffer_size - valid); end: return ret; }
/** * sst_stream_stream - Send msg for a pausing stream * @str_id: stream ID * * This function is called by any function which wants to start * a stream. */ int sst_start_stream(int str_id) { int retval = 0, pvt_id; u32 len = 0; struct ipc_post *msg = NULL; struct ipc_dsp_hdr dsp_hdr; struct stream_info *str_info; pr_debug("sst_start_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; if (str_info->status != STREAM_RUNNING) return -EBADRQC; if (sst_create_ipc_msg(&msg, true)) return -ENOMEM; if (!sst_drv_ctx->use_32bit_ops) { pr_debug("start mrfld"); pvt_id = sst_assign_pvt_id(sst_drv_ctx); pr_debug("pvt_id = %d, pipe id = %d, task = %d\n", pvt_id, str_info->pipe_id, str_info->task_id); sst_fill_header_mrfld(&msg->mrfld_header, IPC_CMD, str_info->task_id, 1, pvt_id); len = sizeof(u16) + sizeof(dsp_hdr); msg->mrfld_header.p.header_low_payload = len; sst_fill_header_dsp(&dsp_hdr, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, sizeof(u16)); memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); memset(msg->mailbox_data + sizeof(dsp_hdr), 0, sizeof(u16)); } else { pr_debug("fill START_STREAM for MFLD/CTP\n"); sst_fill_header(&msg->header, IPC_IA_START_STREAM, 1, str_id); msg->header.part.data = sizeof(u32) + sizeof(u32); memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); memset(msg->mailbox_data + sizeof(u32), 0, sizeof(u32)); } sst_drv_ctx->ops->sync_post_message(msg); 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, pvt_id; struct stream_info *str_info; struct ipc_post *msg = NULL; struct ipc_dsp_hdr dsp_hdr; pr_debug("SST DBG:sst_drop_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; if (str_info->status != STREAM_UN_INIT) { if ((sst_drv_ctx->pci_id != SST_MRFLD_PCI_ID) || (sst_drv_ctx->use_32bit_ops == true)) { str_info->prev = STREAM_UN_INIT; str_info->status = STREAM_INIT; str_info->cumm_bytes = 0; sst_send_sync_msg(IPC_IA_DROP_STREAM, str_id); } else { if (sst_create_ipc_msg(&msg, true)) return -ENOMEM; str_info->prev = STREAM_UN_INIT; str_info->status = STREAM_INIT; str_info->cumm_bytes = 0; pvt_id = sst_assign_pvt_id(sst_drv_ctx); 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_DROP_STREAM_MRFLD, str_info->pipe_id, 0); memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); sst_drv_ctx->ops->sync_post_message(msg); } } else { retval = -EBADRQC; pr_debug("BADQRC for stream, state %x\n", str_info->status); } return retval; }
static int sst_cdev_set_metadata(struct device *dev, unsigned int str_id, struct snd_compr_metadata *metadata) { int retval = 0; struct stream_info *str_info; struct intel_sst_drv *ctx = dev_get_drvdata(dev); dev_dbg(dev, "set metadata for stream %d\n", str_id); str_info = get_stream_info(ctx, str_id); if (!str_info) return -EINVAL; dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id); retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD, IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id, sizeof(*metadata), metadata, NULL, true, true, true, false); 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; struct intel_sst_ops *ops; unsigned long irq_flags; pr_debug("SST DBG:sst_drain_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 && str_info->status != STREAM_INIT && str_info->status != STREAM_PAUSED) { pr_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)) { pr_err("SST ERR: mem allocation failed\n"); return -ENOMEM; } sst_fill_header(&msg->header, IPC_IA_DRAIN_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); 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); } 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 stream_info *str_info; pr_debug("SST DBG:sst_drop_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; if (str_info->status != STREAM_UN_INIT) { str_info->prev = STREAM_UN_INIT; str_info->status = STREAM_INIT; str_info->cumm_bytes = 0; sst_send_sync_msg(IPC_IA_DROP_STREAM, str_id); } else { retval = -EBADRQC; pr_debug("BADQRC for stream, state %x\n", str_info->status); } return retval; }
static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info) { struct stream_info *stream; struct snd_pcm_substream *substream; struct snd_sst_tstamp fw_tstamp; unsigned int str_id; struct intel_sst_drv *ctx = dev_get_drvdata(dev); str_id = info->str_id; stream = get_stream_info(ctx, str_id); if (!stream) return -EINVAL; if (!stream->pcm_substream) return -EINVAL; substream = stream->pcm_substream; memcpy_fromio(&fw_tstamp, ((void *)(ctx->mailbox + ctx->tstamp) + (str_id * sizeof(fw_tstamp))), sizeof(fw_tstamp)); return sst_calc_tstamp(ctx, info, substream, &fw_tstamp); }
/** * sst_stream_stream - Send msg for a pausing stream * @str_id: stream ID * * This function is called by any function which wants to start * a stream. */ int sst_start_stream(int str_id) { int retval = 0; struct ipc_post *msg = NULL; struct stream_info *str_info; pr_debug("sst_start_stream for %d\n", str_id); str_info = get_stream_info(str_id); if (!str_info) return -EINVAL; if (str_info->status != STREAM_RUNNING) return -EBADRQC; if (sst_create_large_msg(&msg)) return -ENOMEM; if (sst_drv_ctx->pci_id == SST_MRFLD_PCI_ID) { sst_fill_header_mrfld(&msg->mrfld_header, IPC_IA_START_STREAM, 1, str_id); msg->mrfld_header.p.header_low_payload = sizeof(u64) + sizeof(u64); memcpy(msg->mailbox_data, &msg->mrfld_header.p.header_high.full, sizeof(u32)); memcpy(msg->mailbox_data + sizeof(u32), &msg->mrfld_header.p.header_low_payload, sizeof(u32)); memset(msg->mailbox_data + sizeof(u64), 0, sizeof(u32)); } else { sst_fill_header(&msg->header, IPC_IA_START_STREAM, 1, str_id); msg->header.part.data = sizeof(u32) + sizeof(u32); memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); memset(msg->mailbox_data + sizeof(u32), 0, sizeof(u32)); } sst_drv_ctx->ops->sync_post_message(msg); 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; }
int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) { struct snd_sst_alloc_mrfld alloc_param; struct snd_sst_params *str_params; struct snd_sst_tstamp fw_tstamp; struct stream_info *str_info; struct snd_sst_alloc_response *response; unsigned int str_id, pipe_id, task_id; int i, num_ch, ret = 0; void *data = NULL; dev_dbg(sst_drv_ctx->dev, "Enter\n"); BUG_ON(!params); str_params = (struct snd_sst_params *)params; memset(&alloc_param, 0, sizeof(alloc_param)); alloc_param.operation = str_params->ops; alloc_param.codec_type = str_params->codec; alloc_param.sg_count = str_params->aparams.sg_count; alloc_param.ring_buf_info[0].addr = str_params->aparams.ring_buf_info[0].addr; alloc_param.ring_buf_info[0].size = str_params->aparams.ring_buf_info[0].size; alloc_param.frag_size = str_params->aparams.frag_size; memcpy(&alloc_param.codec_params, &str_params->sparams, sizeof(struct snd_sst_stream_params)); /* * fill channel map params for multichannel support. * Ideally channel map should be received from upper layers * for multichannel support. * Currently hardcoding as per FW reqm. */ num_ch = sst_get_num_channel(str_params); for (i = 0; i < 8; i++) { if (i < num_ch) alloc_param.codec_params.uc.pcm_params.channel_map[i] = i; else alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF; } str_id = str_params->stream_id; str_info = get_stream_info(sst_drv_ctx, str_id); if (str_info == NULL) { dev_err(sst_drv_ctx->dev, "get stream info returned null\n"); return -EINVAL; } pipe_id = str_params->device_type; task_id = str_params->task; sst_drv_ctx->streams[str_id].pipe_id = pipe_id; sst_drv_ctx->streams[str_id].task_id = task_id; sst_drv_ctx->streams[str_id].num_ch = num_ch; if (sst_drv_ctx->info.lpe_viewpt_rqd) alloc_param.ts = sst_drv_ctx->info.mailbox_start + sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); else alloc_param.ts = sst_drv_ctx->mailbox_add + sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", alloc_param.ts); dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", pipe_id, task_id); /* allocate device type context */ sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, str_id, alloc_param.operation, 0); dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), &alloc_param, data, true, true, false, true); if (ret < 0) { dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); /* alloc failed, so reset the state to uninit */ str_info->status = STREAM_UN_INIT; str_id = ret; } else if (data) { response = (struct snd_sst_alloc_response *)data; ret = response->str_type.result; if (!ret) goto out; dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); if (ret == SST_ERR_STREAM_IN_USE) { dev_err(sst_drv_ctx->dev, "FW not in clean state, send free for:%d\n", str_id); sst_free_stream(sst_drv_ctx, str_id); } str_id = -ret; } out: kfree(data); return str_id; }
static int fdk_aac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt) { FDKAACDecContext *s = avctx->priv_data; AVFrame *frame = data; int ret; AAC_DECODER_ERROR err; UINT valid = avpkt->size; uint8_t *buf, *tmpptr = NULL; int buf_size; err = aacDecoder_Fill(s->handle, &avpkt->data, &avpkt->size, &valid); if (err != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "aacDecoder_Fill() failed: %x\n", err); return AVERROR_INVALIDDATA; } if (s->initialized) { frame->nb_samples = avctx->frame_size; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; buf = frame->extended_data[0]; buf_size = avctx->channels * frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt); } else { buf_size = 50 * 1024; buf = tmpptr = av_malloc(buf_size); if (!buf) return AVERROR(ENOMEM); } err = aacDecoder_DecodeFrame(s->handle, (INT_PCM *) buf, buf_size, 0); if (err == AAC_DEC_NOT_ENOUGH_BITS) { ret = avpkt->size - valid; goto end; } if (err != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "aacDecoder_DecodeFrame() failed: %x\n", err); ret = AVERROR_UNKNOWN; goto end; } if (!s->initialized) { if ((ret = get_stream_info(avctx)) < 0) goto end; s->initialized = 1; frame->nb_samples = avctx->frame_size; } if (tmpptr) { frame->nb_samples = avctx->frame_size; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) goto end; memcpy(frame->extended_data[0], tmpptr, avctx->channels * avctx->frame_size * av_get_bytes_per_sample(avctx->sample_fmt)); } *got_frame_ptr = 1; ret = avpkt->size - valid; end: av_free(tmpptr); return ret; }
/** * 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; }