@@ -62,24 +62,66 @@ struct dai_data {
6262 struct dai * dai ;
6363 struct dma * dma ;
6464 uint32_t period_bytes ;
65- completion_t complete ;
6665 int xrun ; /* true if we are doing xrun recovery */
6766 int pointer_init ; /* true if buffer pointer was initialized */
6867
69- uint32_t last_bytes ; /* the last bytes(<period size) it copies. */
7068 uint32_t dai_pos_blks ; /* position in bytes (nearest block) */
7169
7270 volatile uint64_t * dai_pos ; /* host can read back this value without IPC */
7371 uint64_t wallclock ; /* wall clock at stream start */
7472};
7573
74+ static void dai_buffer_process (struct comp_dev * dev )
75+ {
76+ struct dai_data * dd = comp_get_drvdata (dev );
77+ struct comp_buffer * dma_buffer ;
78+ void * buffer_ptr ;
79+
80+ if (dev -> params .direction == SOF_IPC_STREAM_PLAYBACK ) {
81+ dma_buffer = list_first_item (& dev -> bsource_list ,
82+ struct comp_buffer , sink_list );
83+
84+ /* recalc available buffer space */
85+ comp_update_buffer_consume (dma_buffer , dd -> period_bytes );
86+
87+ buffer_ptr = dma_buffer -> r_ptr ;
88+
89+ /* make sure there is available bytes for next period */
90+ if (dma_buffer -> avail < dd -> period_bytes ) {
91+ trace_dai_error ("xru" );
92+ comp_underrun (dev , dma_buffer , dd -> period_bytes , 0 );
93+ }
94+ } else {
95+ dma_buffer = list_first_item (& dev -> bsink_list ,
96+ struct comp_buffer , source_list );
97+
98+ /* recalc available buffer space */
99+ comp_update_buffer_produce (dma_buffer , dd -> period_bytes );
100+
101+ buffer_ptr = dma_buffer -> w_ptr ;
102+
103+ /* make sure there is free bytes for next period */
104+ if (dma_buffer -> free < dd -> period_bytes ) {
105+ trace_dai_error ("xro" );
106+ comp_overrun (dev , dma_buffer , dd -> period_bytes , 0 );
107+ }
108+ }
109+
110+ /* update host position (in bytes offset) for drivers */
111+ dev -> position += dd -> period_bytes ;
112+ if (dd -> dai_pos ) {
113+ dd -> dai_pos_blks += dd -> period_bytes ;
114+ * dd -> dai_pos = dd -> dai_pos_blks +
115+ buffer_ptr - dma_buffer -> addr ;
116+ }
117+ }
118+
76119/* this is called by DMA driver every time descriptor has completed */
77120static void dai_dma_cb (void * data , uint32_t type , struct dma_sg_elem * next )
78121{
79122 struct comp_dev * dev = (struct comp_dev * )data ;
80123 struct dai_data * dd = comp_get_drvdata (dev );
81124 struct comp_buffer * dma_buffer ;
82- uint32_t copied_size ;
83125
84126 tracev_dai ("irq" );
85127
@@ -91,9 +133,6 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
91133
92134 /* tell DMA not to reload */
93135 next -> size = DMA_RELOAD_END ;
94-
95- /* inform waiters */
96- wait_completed (& dd -> complete );
97136 }
98137
99138 /* is our pipeline handling an XRUN ? */
@@ -111,50 +150,7 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
111150 return ;
112151 }
113152
114- if (dev -> params .direction == SOF_IPC_STREAM_PLAYBACK ) {
115- dma_buffer = list_first_item (& dev -> bsource_list ,
116- struct comp_buffer , sink_list );
117-
118- copied_size = dd -> last_bytes ? dd -> last_bytes : dd -> period_bytes ;
119-
120- /* recalc available buffer space */
121- comp_update_buffer_consume (dma_buffer , copied_size );
122-
123- /* update host position(in bytes offset) for drivers */
124- dev -> position += copied_size ;
125- if (dd -> dai_pos ) {
126- dd -> dai_pos_blks += copied_size ;
127- * dd -> dai_pos = dd -> dai_pos_blks +
128- dma_buffer -> r_ptr - dma_buffer -> addr ;
129- }
130-
131- /* make sure there is availble bytes for next period */
132- if (dma_buffer -> avail < dd -> period_bytes ) {
133- trace_dai_error ("xru" );
134- comp_underrun (dev , dma_buffer , copied_size , 0 );
135- }
136-
137- } else {
138- dma_buffer = list_first_item (& dev -> bsink_list ,
139- struct comp_buffer , source_list );
140-
141- /* recalc available buffer space */
142- comp_update_buffer_produce (dma_buffer , dd -> period_bytes );
143-
144- /* update positions */
145- dev -> position += dd -> period_bytes ;
146- if (dd -> dai_pos ) {
147- dd -> dai_pos_blks += dd -> period_bytes ;
148- * dd -> dai_pos = dd -> dai_pos_blks +
149- dma_buffer -> w_ptr - dma_buffer -> addr ;
150- }
151-
152- /* make sure there is free bytes for next period */
153- if (dma_buffer -> free < dd -> period_bytes ) {
154- trace_dai_error ("xro" );
155- comp_overrun (dev , dma_buffer , dd -> period_bytes , 0 );
156- }
157- }
153+ dai_buffer_process (dev );
158154
159155 /* notify pipeline that DAI needs its buffer processed */
160156 if (dev -> state == COMP_STATE_ACTIVE )
@@ -221,7 +217,6 @@ static struct comp_dev *dai_new(struct sof_ipc_comp *comp)
221217 list_init (& dd -> config .elem_list );
222218 dd -> dai_pos = NULL ;
223219 dd -> dai_pos_blks = 0 ;
224- dd -> last_bytes = 0 ;
225220 dd -> xrun = 0 ;
226221 dd -> pointer_init = 0 ;
227222
@@ -507,7 +502,6 @@ static int dai_reset(struct comp_dev *dev)
507502 if (dd -> dai_pos )
508503 * dd -> dai_pos = 0 ;
509504 dd -> dai_pos = NULL ;
510- dd -> last_bytes = 0 ;
511505 dd -> wallclock = 0 ;
512506 dev -> position = 0 ;
513507 dd -> xrun = 0 ;
@@ -554,13 +548,12 @@ static void dai_pointer_init(struct comp_dev *dev)
554548static int dai_comp_trigger (struct comp_dev * dev , int cmd )
555549{
556550 struct dai_data * dd = comp_get_drvdata (dev );
551+ struct comp_buffer * dma_buffer ;
557552 int ret ;
558553
559554 trace_dai ("trg" );
560555 tracev_value (cmd );
561556
562- wait_init (& dd -> complete );
563-
564557 ret = comp_set_state (dev , cmd );
565558 if (ret < 0 )
566559 return ret ;
@@ -590,14 +583,22 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
590583 * this is only supported at capture mode.
591584 */
592585 if (dev -> params .direction == SOF_IPC_STREAM_CAPTURE ) {
593- struct comp_buffer * dma_buffer =
594- list_first_item ( & dev -> bsink_list ,
595- struct comp_buffer , source_list );
586+ dma_buffer = list_first_item ( & dev -> bsink_list ,
587+ struct comp_buffer ,
588+ source_list );
596589 buffer_zero (dma_buffer );
597590 }
598591
599592 /* only start the DAI if we are not XRUN handling */
600593 if (dd -> xrun == 0 ) {
594+ /* set valid buffer pointer */
595+ dai_buffer_process (dev );
596+
597+ /* recover valid start position */
598+ ret = dma_release (dd -> dma , dd -> chan );
599+ if (ret < 0 )
600+ return ret ;
601+
601602 /* start the DAI */
602603 ret = dma_start (dd -> dma , dd -> chan );
603604 if (ret < 0 )
@@ -613,26 +614,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
613614 case COMP_TRIGGER_XRUN :
614615 trace_dai ("txr" );
615616 dd -> xrun = 1 ;
616- /* stop the DAI unconditionally */
617- dai_trigger (dd -> dai , COMP_TRIGGER_STOP , dev -> params .direction );
618- ret = dma_stop (dd -> dma , dd -> chan );
619- break ;
617+
618+ /* fallthrough */
620619 case COMP_TRIGGER_PAUSE :
621620 case COMP_TRIGGER_STOP :
622621 trace_dai ("tsp" );
623- wait_init (& dd -> complete );
624-
625- /* wait for DMA to complete */
626- dd -> complete .timeout = dev -> pipeline -> ipc_pipe .deadline ;
627- ret = wait_for_completion_timeout (& dd -> complete );
628- if (ret < 0 ) {
629- trace_dai_error ("ed0" );
630- trace_error_value (cmd );
631- /* forced stop of DMA+DAI to avoid refcount issues */
632- dai_trigger (dd -> dai , COMP_TRIGGER_STOP ,
633- dev -> params .direction );
634- ret = dma_stop (dd -> dma , dd -> chan );
635- }
622+ ret = dma_stop (dd -> dma , dd -> chan );
623+ dai_trigger (dd -> dai , COMP_TRIGGER_STOP , dev -> params .direction );
636624 break ;
637625 default :
638626 break ;
0 commit comments