@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
165165 * currently in use (if any). */
166166 hw -> rate_min = 5512 ;
167167 hw -> rate_max = 192000 ;
168- /* if the other stream is active, then we can only
169- * support what it is currently using .
170- * FIXME: I lied. This comment is wrong. We can support
171- * anything that works with the same serial format, ie.
172- * when recording 24 bit sound we can well play 16 bit
173- * sound at the same time iff using the same transfer mode .
168+ /* If the other stream is already prepared, keep this stream
169+ * on the same duplex format and rate .
170+ *
171+ * i2sbus_pcm_prepare() still programs one shared transport
172+ * configuration for both directions, so mixed duplex formats
173+ * are not supported here .
174174 */
175175 if (other -> active ) {
176- /* FIXME: is this guaranteed by the alsa api? */
177176 hw -> formats &= pcm_format_to_bits (i2sdev -> format );
178- /* see above, restrict rates to the one we already have */
177+ /* Restrict rates to the one already in use. */
179178 hw -> rate_min = i2sdev -> rate ;
180179 hw -> rate_max = i2sdev -> rate ;
181180 }
@@ -283,6 +282,22 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
283282}
284283#endif
285284
285+ static void i2sbus_pcm_clear_active (struct i2sbus_dev * i2sdev , int in )
286+ {
287+ struct pcm_info * pi ;
288+
289+ guard (mutex )(& i2sdev -> lock );
290+
291+ get_pcm_info (i2sdev , in , & pi , NULL );
292+ pi -> active = 0 ;
293+ }
294+
295+ static inline int i2sbus_hw_params (struct snd_pcm_substream * substream , int in )
296+ {
297+ i2sbus_pcm_clear_active (snd_pcm_substream_chip (substream ), in );
298+ return 0 ;
299+ }
300+
286301static inline int i2sbus_hw_free (struct snd_pcm_substream * substream , int in )
287302{
288303 struct i2sbus_dev * i2sdev = snd_pcm_substream_chip (substream );
@@ -291,14 +306,25 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
291306 get_pcm_info (i2sdev , in , & pi , NULL );
292307 if (pi -> dbdma_ring .stopping )
293308 i2sbus_wait_for_stop (i2sdev , pi );
309+ i2sbus_pcm_clear_active (i2sdev , in );
294310 return 0 ;
295311}
296312
313+ static int i2sbus_playback_hw_params (struct snd_pcm_substream * substream )
314+ {
315+ return i2sbus_hw_params (substream , 0 );
316+ }
317+
297318static int i2sbus_playback_hw_free (struct snd_pcm_substream * substream )
298319{
299320 return i2sbus_hw_free (substream , 0 );
300321}
301322
323+ static int i2sbus_record_hw_params (struct snd_pcm_substream * substream )
324+ {
325+ return i2sbus_hw_params (substream , 1 );
326+ }
327+
302328static int i2sbus_record_hw_free (struct snd_pcm_substream * substream )
303329{
304330 return i2sbus_hw_free (substream , 1 );
@@ -335,7 +361,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
335361 return - EINVAL ;
336362
337363 runtime = pi -> substream -> runtime ;
338- pi -> active = 1 ;
364+ pi -> active = 0 ;
339365 if (other -> active &&
340366 ((i2sdev -> format != runtime -> format )
341367 || (i2sdev -> rate != runtime -> rate )))
@@ -450,9 +476,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
450476
451477 /* early exit if already programmed correctly */
452478 /* not locking these is fine since we touch them only in this function */
453- if (in_le32 (& i2sdev -> intfregs -> serial_format ) == sfr
454- && in_le32 (& i2sdev -> intfregs -> data_word_sizes ) == dws )
479+ if (in_le32 (& i2sdev -> intfregs -> serial_format ) == sfr &&
480+ in_le32 (& i2sdev -> intfregs -> data_word_sizes ) == dws ) {
481+ pi -> active = 1 ;
455482 return 0 ;
483+ }
456484
457485 /* let's notify the codecs about clocks going away.
458486 * For now we only do mastering on the i2s cell... */
@@ -490,6 +518,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
490518 if (cii -> codec -> switch_clock )
491519 cii -> codec -> switch_clock (cii , CLOCK_SWITCH_SLAVE );
492520
521+ pi -> active = 1 ;
493522 return 0 ;
494523}
495524
@@ -734,6 +763,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
734763static const struct snd_pcm_ops i2sbus_playback_ops = {
735764 .open = i2sbus_playback_open ,
736765 .close = i2sbus_playback_close ,
766+ .hw_params = i2sbus_playback_hw_params ,
737767 .hw_free = i2sbus_playback_hw_free ,
738768 .prepare = i2sbus_playback_prepare ,
739769 .trigger = i2sbus_playback_trigger ,
@@ -802,6 +832,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
802832static const struct snd_pcm_ops i2sbus_record_ops = {
803833 .open = i2sbus_record_open ,
804834 .close = i2sbus_record_close ,
835+ .hw_params = i2sbus_record_hw_params ,
805836 .hw_free = i2sbus_record_hw_free ,
806837 .prepare = i2sbus_record_prepare ,
807838 .trigger = i2sbus_record_trigger ,
0 commit comments