[Sound-open-firmware] [PATCH 23/25] dai: add R/W pointer check for dai copy

Liam Girdwood liam.r.girdwood at linux.intel.com
Wed Feb 8 13:13:52 CET 2017


On Tue, 2017-02-07 at 22:03 +0800, Keyon Jie wrote:
> We should only copy when there is data, after copied the last bytes
> or period, we will stop the dai and ssp, and trigger the pipeline
> finish, which will notify host side the last read pointer and let
> host side send trigger stop ipc.
> 
> Signed-off-by: Keyon Jie <yang.jie at linux.intel.com>
> ---
>  src/audio/dai.c | 44 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 39 insertions(+), 5 deletions(-)
> 
> diff --git a/src/audio/dai.c b/src/audio/dai.c
> index 3b2ea30..a9b46a5 100644
> --- a/src/audio/dai.c
> +++ b/src/audio/dai.c
> @@ -69,6 +69,7 @@ struct dai_data {
>  	volatile uint64_t *dai_pos; /* host can read back this value without IPC */
>  };
>  
> +static int dai_cmd(struct comp_dev *dev, int cmd, void *data);
>  /* this is called by DMA driver every time descriptor has completed */
>  static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>  {
> @@ -76,17 +77,22 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>  	struct dai_data *dd = comp_get_drvdata(dev);
>  	struct period_desc *dma_period_desc;
>  	struct comp_buffer *dma_buffer;
> +	uint32_t copied_size;
>  
>  	if (dd->direction == STREAM_DIRECTION_PLAYBACK) {
>  		dma_buffer = list_first_item(&dev->bsource_list,
>  			struct comp_buffer, sink_list);
>  
>  		dma_period_desc = &dma_buffer->desc.sink_period;
> -		dma_buffer->r_ptr += dma_period_desc->size;
> +		copied_size = dd->last_bytes ? dd->last_bytes : dma_period_desc->size;
> +		dma_buffer->r_ptr += copied_size;
>  
>  		/* check for end of buffer */
> -		if (dma_buffer->r_ptr >= dma_buffer->end_addr)
> +		if (dma_buffer->r_ptr >= dma_buffer->end_addr) {
>  			dma_buffer->r_ptr = dma_buffer->addr;
> +			/* update host position(in bytes offset) for drivers */
> +			dd->dai_pos_blks += dma_buffer->desc.size;
> +		}
>  
>  #if 0
>  		// TODO: move this to new trace mechanism
> @@ -109,16 +115,17 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>  		dma_buffer->w_ptr += dma_period_desc->size;
>  
>  		/* check for end of buffer */
> -		if (dma_buffer->w_ptr >= dma_buffer->end_addr)
> +		if (dma_buffer->w_ptr >= dma_buffer->end_addr) {
>  			dma_buffer->w_ptr = dma_buffer->addr;
> +			/* update host position(in bytes offset) for drivers */
> +			dd->dai_pos_blks += dma_buffer->desc.size;
> +		}
>  
>  #if 0
>  		// TODO: move this to new trace mechanism
>  		trace_value((uint32_t)(dma_buffer->w_ptr - dma_buffer->addr));
>  #endif
>  
> -		/* update host position(in bytes offset) for drivers */
> -		dd->dai_pos_blks += dma_period_desc->size;
>  		if (dd->dai_pos)
>  			*dd->dai_pos = dd->dai_pos_blks +
>  				dma_buffer->w_ptr - dma_buffer->addr;
> @@ -127,9 +134,36 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>  		comp_update_buffer_produce(dma_buffer);
>  	}
>  
> +	if (dd->direction == STREAM_DIRECTION_PLAYBACK &&
> +				dma_buffer->avail < dma_period_desc->size) {
> +		/* end of stream, finish */
> +		if (dma_buffer->avail == 0) {
> +			dai_cmd(dev, COMP_CMD_STOP, NULL);

newline

> +			/* stop dma immediatly */
> +			next->size = 0xFFFFFFFF;

magic number

> +			/* let any waiters know we have completed */
> +			wait_completed(&dev->pipeline->complete);
> +			return;
> +		} else {
> +			/* drain the last bytes */
> +			next->src = (uint32_t)dma_buffer->r_ptr;
> +			next->dest = dai_fifo(dd->ssp, dd->direction);
> +			next->size = dma_buffer->avail;
> +
> +			dd->last_bytes = next->size;
> +
> +			goto next_copy;
> +
> +		}
> +
> +	}
>  	/* notify pipeline that DAI needs it's buffer filled */
>  //	if (dev->state == COMP_STATE_RUNNING)
>  		pipeline_schedule_copy(dev->pipeline, dev);
> +
> +next_copy:
> +
> +	return;
>  }
>  
>  static struct comp_dev *dai_new_ssp(uint32_t type, uint32_t index,




More information about the Sound-open-firmware mailing list