Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/sound/soc/intel/atom/sst/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 13 kB image not shown  

Quelle  sst_stream.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  sst_stream.c - Intel SST Driver for audio engine
 *
 *  Copyright (C) 2008-14 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>
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/compress_driver.h>
#include <asm/platform_sst_audio.h>
#include "../sst-mfld-platform.h"
#include "sst.h"

int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
{
 struct snd_pcm_params *pcm_params;
 struct snd_sst_params *str_params;
 struct snd_sst_tstamp fw_tstamp;
 struct stream_info *str_info;
 int i, num_ch, str_id;

 dev_dbg(sst_drv_ctx->dev, "Enter\n");

 str_params = (struct snd_sst_params *)params;
 str_id = str_params->stream_id;
 str_info = get_stream_info(sst_drv_ctx, str_id);
 if (!str_info)
  return -EINVAL;

 memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param));
 str_info->alloc_param.operation = str_params->ops;
 str_info->alloc_param.codec_type = str_params->codec;
 str_info->alloc_param.sg_count = str_params->aparams.sg_count;
 str_info->alloc_param.ring_buf_info[0].addr =
  str_params->aparams.ring_buf_info[0].addr;
 str_info->alloc_param.ring_buf_info[0].size =
  str_params->aparams.ring_buf_info[0].size;
 str_info->alloc_param.frag_size = str_params->aparams.frag_size;

 memcpy(&str_info->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);
 pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params;
 for (i = 0; i < 8; i++) {
  if (i < num_ch)
   pcm_params->channel_map[i] = i;
  else
   pcm_params->channel_map[i] = 0xff;
 }

 sst_drv_ctx->streams[str_id].status = STREAM_INIT;
 sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT;
 sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type;
 sst_drv_ctx->streams[str_id].task_id = str_params->task;
 sst_drv_ctx->streams[str_id].num_ch = num_ch;

 if (sst_drv_ctx->info.lpe_viewpt_rqd)
  str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start +
   sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
 else
  str_info->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",
   str_info->alloc_param.ts);
 dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
   str_info->pipe_id, str_info->task_id);

 return sst_realloc_stream(sst_drv_ctx, str_id);
}

/**
 * sst_realloc_stream - Send msg for (re-)allocating a stream using the
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @str_id: stream ID
 *
 * Send a msg for (re-)allocating a stream using the parameters previously
 * passed to sst_alloc_stream_mrfld() for the same stream ID.
 * Return: 0 or negative errno value.
 */

int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
{
 struct snd_sst_alloc_response *response;
 struct stream_info *str_info;
 void *data = NULL;
 int ret;

 str_info = get_stream_info(sst_drv_ctx, str_id);
 if (!str_info)
  return -EINVAL;

 dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
  str_id, str_info->pipe_id);

 ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
   IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id,
   sizeof(str_info->alloc_param), &str_info->alloc_param,
   &data, truetruefalsetrue);

 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;
}

/**
 * sst_start_stream - Send msg for a starting stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @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, truetruetruefalse);

 return retval;
}

int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
  struct snd_sst_bytes_v2 *bytes)
struct ipc_post *msg = NULL;
 u32 length;
 int pvt_id, ret = 0;
 struct sst_block *block = NULL;
 u8 bytes_block = bytes->block;

 dev_dbg(sst_drv_ctx->dev,
  "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
  bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id,
  bytes->pipe_id, bytes->len);

 if (sst_create_ipc_msg(&msg, true))
  return -ENOMEM;

 pvt_id = sst_assign_pvt_id(sst_drv_ctx);
 sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
   bytes->task_id, 1, pvt_id);
 msg->mrfld_header.p.header_high.part.res_rqd = bytes_block;
 length = bytes->len;
 msg->mrfld_header.p.header_low_payload = length;
 dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
 memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
 if (bytes_block) {
  block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
  if (block == NULL) {
   kfree(msg);
   ret = -ENOMEM;
   goto out;
  }
 }

 sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
 dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
   msg->mrfld_header.p.header_low_payload);

 if (bytes_block) {
  ret = sst_wait_timeout(sst_drv_ctx, block);
  if (ret) {
   dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
   sst_free_block(sst_drv_ctx, block);
   goto out;
  }
 }
 if (bytes->type == SND_SST_BYTES_GET) {
  /*
 * copy the reply and send back
 * we need to update only sz and payload
 */

  if (bytes_block) {
   unsigned char *r = block->data;

   dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
     bytes->len);
   memcpy(bytes->bytes, r, bytes->len);
  }
 }
 if (bytes_block)
  sst_free_block(sst_drv_ctx, block);
out:
 test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
 return ret;
}

/**
 * sst_pause_stream - Send msg for a pausing stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @str_id: stream ID
 *
 * This function is called by any function which wants to pause
 * an already running stream.
 */

int sst_pause_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_pause_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_PAUSED)
  return 0;
 if (str_info->status == STREAM_RUNNING ||
  str_info->status == STREAM_INIT) {
  if (str_info->prev == STREAM_UN_INIT)
   return -EBADRQC;

  retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
    IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
    0, NULL, NULL, truetruefalsetrue);

  if (retval == 0) {
   str_info->prev = str_info->status;
   str_info->status = 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_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
 }

 return retval;
}

/**
 * sst_resume_stream - Send msg for resuming stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @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->resume_status == STREAM_PAUSED &&
     str_info->resume_prev == STREAM_RUNNING) {
  /*
 * Stream was running before suspend and re-created on resume,
 * start it to get back to running state.
 */

  dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n");
  str_info->status = STREAM_RUNNING;
  str_info->prev = STREAM_PAUSED;
  retval = sst_start_stream(sst_drv_ctx, str_id);
  str_info->resume_status = STREAM_UN_INIT;
 } else if (str_info->resume_status == STREAM_PAUSED &&
     str_info->resume_prev == STREAM_INIT) {
  /*
 * Stream was idle before suspend and re-created on resume,
 * keep it as is.
 */

  dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n");
  str_info->status = STREAM_INIT;
  str_info->prev = STREAM_PAUSED;
  str_info->resume_status = STREAM_UN_INIT;
 } else 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,
    truetruefalsetrue);

  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_drop_stream - Send msg for stopping stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @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,
    truetruetruefalse);
 } else {
  retval = -EBADRQC;
  dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
    str_info->status);
 }
 return retval;
}

/**
 * sst_drain_stream - Send msg for draining stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @str_id: stream ID
 * @partial_drain: boolean indicating if a gapless transition is taking place
 *
 * 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, truetruefalsefalse);
 /*
 * 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;
}

/**
 * sst_free_stream - Frees a stream
 * @sst_drv_ctx: intel_sst_drv context pointer
 * @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;

 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;

 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_dbg(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, truetruefalsetrue);

  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;
}

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.