]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ASoC: fsl: imx-ssi: omit ssi counter to avoid harm in unbalanced situation
authorOskar Schirmer <oskar@scara.com>
Sat, 16 Nov 2013 07:52:25 +0000 (07:52 +0000)
committerMark Brown <broonie@linaro.org>
Mon, 2 Dec 2013 11:57:02 +0000 (11:57 +0000)
Unbalanced calls to imx_ssi_trigger() may result in endless
SSI activity and thus provoke eternal sound. While on the first glance,
the switch statement looks pretty symmetric, the SUSPEND/RESUME
pair is not: the suspend case comes along snd_pcm_suspend_all(),
which for fsl/imx-pcm-fiq is called only at snd_soc_suspend(),
but the resume case originates straight from the SNDRV_PCM_IOCTL_RESUME.
This way userland may provoke an unbalanced resume, which might cause
the ssi->enabled counter to increase and never return to zero again,
so eventually SSI_SCR_SSIEN is never disabled.

As the information on whether to enable the SSI or not is contained
in the two bits for TE/RE, we save all the software mirroring of
hardware state here and simply use the hardware register itself
to keep the state of whether someone is currently playing or capturing.

This is essentially the same stuff as in sound/soc/fsl/imx-pcm-fiq.c
which I send a patch for three days ago. Astonishing enough this
highly fragile scheme is used twice in parallel to serve the very
same control function, synchronously: Once out of sync you are lost
until reboot.

Note, that these fixes wont prevent state machine distortion on alsa
level to cut sound or the like. It just makes sure we have a chance
to synchronise again later on.

Signed-off-by: Oskar Schirmer <oskar@scara.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h

index cc7376f87f888b5db47d70d84826fb7e426d7863..6336757e967ac6009086a4f07173170967a41481 100644 (file)
@@ -304,8 +304,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        scr |= SSI_SCR_RE;
                sier |= sier_bits;
 
-               if (++ssi->enabled == 1)
-                       scr |= SSI_SCR_SSIEN;
+               scr |= SSI_SCR_SSIEN;
 
                break;
 
@@ -318,7 +317,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        scr &= ~SSI_SCR_RE;
                sier &= ~sier_bits;
 
-               if (--ssi->enabled == 0)
+               if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
                        scr &= ~SSI_SCR_SSIEN;
 
                break;
index 560c40fc9ebbb50241e3732f3a76ece064178bf2..be6562365b6a971a08efe55e3c1d7c49f0c0a874 100644 (file)
@@ -213,7 +213,6 @@ struct imx_ssi {
 
        int fiq_init;
        int dma_init;
-       int enabled;
 };
 
 #endif /* _IMX_SSI_H */