summaryrefslogtreecommitdiffstats
path: root/sound/pci/lola
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-03 17:02:35 +0200
committerTakashi Iwai <tiwai@suse.de>2011-05-03 17:02:35 +0200
commitc7aad3c317afc05418414c95e877173799145d0b (patch)
treed091d02fdbd48f6b38207149aa7c07719d7d2b9c /sound/pci/lola
parent7e79f2267605e59492fef92b966dddc3c6a68b41 (diff)
ALSA: lola - Add sync in loop implementation
For assuring the synchronized state with the pause operation, loop over the all linked streams and waits until all get ready in a loop. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/lola')
-rw-r--r--sound/pci/lola/lola_pcm.c76
1 files changed, 59 insertions, 17 deletions
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 6be6b7e8f56..5c0014cbff0 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -121,27 +121,69 @@ static int lola_stream_wait_for_fifo(struct lola *chip,
return -EIO;
}
-static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
+/* sync for FIFO ready/empty for all linked streams;
+ * clear paused flag when FIFO gets ready again
+ */
+static int lola_sync_wait_for_fifo(struct lola *chip,
+ struct snd_pcm_substream *substream,
+ bool ready)
{
- if (str->prepared) {
- str->prepared = 0;
+ unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+ unsigned long end_time = jiffies + msecs_to_jiffies(200);
+ struct snd_pcm_substream *s;
+ int pending = 0;
+
+ while (time_before(jiffies, end_time)) {
+ pending = 0;
+ snd_pcm_group_for_each_entry(s, substream) {
+ struct lola_stream *str;
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ str = lola_get_stream(s);
+ if (str->prepared && str->paused) {
+ unsigned int reg;
+ reg = lola_dsd_read(chip, str->dsd, STS);
+ if ((reg & LOLA_DSD_STS_FIFORDY) != val) {
+ pending = str->dsd + 1;
+ break;
+ }
+ if (ready)
+ str->paused = 0;
+ }
+ }
+ if (!pending)
+ return 0;
+ msleep(1);
+ }
+ printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+ return -EIO;
+}
- if (str->paused) {
- /* finish pause - prepare for a new resume
- * move this code later to trigger function,
- * as this is also needed when resuming from pause
- */
- str->paused = 0;
- /* implement later loop for all streams */
- lola_stream_wait_for_fifo(chip, str, false);
+/* finish pause - prepare for a new resume */
+static void lola_sync_pause(struct lola *chip,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_substream *s;
+
+ lola_sync_wait_for_fifo(chip, substream, false);
+ snd_pcm_group_for_each_entry(s, substream) {
+ struct lola_stream *str;
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ str = lola_get_stream(s);
+ if (str->paused && str->prepared)
lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN |
LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
- /* end loop */
- /* implement later once more loop for all streams */
- lola_stream_wait_for_fifo(chip, str, true);
- /* end loop */
- /* end finish pause */
- }
+ }
+ lola_sync_wait_for_fifo(chip, substream, true);
+}
+
+static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
+{
+ if (str->prepared) {
+ if (str->paused)
+ lola_sync_pause(chip, str->substream);
+ str->prepared = 0;
lola_dsd_write(chip, str->dsd, CTL,
LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
lola_stream_wait_for_fifo(chip, str, false);