ALSA: lola - Add SRC refcounting
authorTakashi Iwai <tiwai@suse.de>
Tue, 3 May 2011 14:59:27 +0000 (16:59 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 3 May 2011 14:59:27 +0000 (16:59 +0200)
Added the refcounting for the exclusive SRC control.
Also, fixed the possible stall after PCM pause operations.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/lola/lola.h
sound/pci/lola/lola_pcm.c

index bc8110ff6b467fe320a5a777669ecea2a413e852..180c2c124620c41010e233ab66849fef066a0ff1 100644 (file)
@@ -306,6 +306,7 @@ struct lola_stream {
        /* flags */
        unsigned int opened:1;
        unsigned int prepared:1;
+       unsigned int paused:1;
        unsigned int running:1;
 };
 
@@ -356,6 +357,8 @@ struct lola {
 
        /* clock */
        struct lola_clock_widget clock;
+       int ref_count_rate;
+       unsigned int sample_rate;
 
        /* mixer */
        struct lola_mixer_widget mixer;
@@ -370,7 +373,6 @@ struct lola {
        unsigned int sample_rate_max;
 
        /* flags */
-       unsigned int running :1;
        unsigned int initialized :1;
        unsigned int cold_reset :1;
 
index 4bb5b5bd6371f78fda1adb900d9e4e764643d0b3..6be6b7e8f5676a1a37867ed4c8aa7920f6b0f0e4 100644 (file)
@@ -126,6 +126,22 @@ static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
        if (str->prepared) {
                str->prepared = 0;
 
+               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);
+                       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_dsd_write(chip, str->dsd, CTL,
                               LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
                lola_stream_wait_for_fifo(chip, str, false);
@@ -178,12 +194,17 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
        str->opened = 1;
        runtime->hw = lola_pcm_hw;
        runtime->hw.channels_max = pcm->num_streams - str->index;
-       runtime->hw.rate_min = chip->sample_rate_min;
-       runtime->hw.rate_max = chip->sample_rate_max;
+       if (chip->sample_rate) {
+               /* sample rate is locked */
+               runtime->hw.rate_min = chip->sample_rate;
+               runtime->hw.rate_max = chip->sample_rate;
+       } else {
+               runtime->hw.rate_min = chip->sample_rate_min;
+               runtime->hw.rate_max = chip->sample_rate_max;
+       }
+       chip->ref_count_rate++;
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       /* period size = multiple of chip->granularity (8, 16 or 32 frames)
-        * use LOLA_GRANULARITY_MAX = 32 for instance
-        */
+       /* period size = multiple of chip->granularity (8, 16 or 32 frames)*/
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
                                   chip->granularity);
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
@@ -215,6 +236,10 @@ static int lola_pcm_close(struct snd_pcm_substream *substream)
                str->substream = NULL;
                str->opened = 0;
        }
+       if (--chip->ref_count_rate == 0) {
+               /* release sample rate */
+               chip->sample_rate = 0;
+       }
        mutex_unlock(&chip->open_mutex);
        return 0;
 }
@@ -427,6 +452,11 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
        if (err < 0)
                return err;
 
+       err = lola_set_sample_rate(chip, runtime->rate);
+       if (err < 0)
+               return err;
+       chip->sample_rate = runtime->rate;      /* sample rate gets locked */
+
        err = lola_set_stream_config(chip, str, runtime->channels);
        if (err < 0)
                return err;
@@ -447,6 +477,7 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_pcm_substream *s;
        unsigned int start;
        unsigned int tstamp;
+       bool sync_streams;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -463,7 +494,12 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                return -EINVAL;
        }
 
-       tstamp = lola_get_tstamp(chip, false);
+       /*
+        * sample correct synchronization is only needed starting several
+        * streams on stop or if only one stream do as quick as possible
+        */
+       sync_streams = (start && snd_pcm_stream_linked(substream));
+       tstamp = lola_get_tstamp(chip, !sync_streams);
        spin_lock(&chip->reg_lock);
        snd_pcm_group_for_each_entry(s, substream) {
                if (s->pcm->card != substream->pcm->card)
@@ -474,6 +510,7 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                else
                        lola_stream_stop(chip, str, tstamp);
                str->running = start;
+               str->paused = !start;
                snd_pcm_trigger_done(s, substream);
        }
        spin_unlock(&chip->reg_lock);