summary refs log tree commit diff
path: root/sound/pci/lola
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-03 16:59:27 +0200
committerTakashi Iwai <tiwai@suse.de>2011-05-03 16:59:27 +0200
commit7e79f2267605e59492fef92b966dddc3c6a68b41 (patch)
tree65a091902884420f475ec284ef3b77a021ab647f /sound/pci/lola
parent8bd172dc96fba8ba5a7560afdc1ff7461c278e86 (diff)
downloadlinux-7e79f2267605e59492fef92b966dddc3c6a68b41.tar.gz
ALSA: lola - Add SRC refcounting
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>
Diffstat (limited to 'sound/pci/lola')
-rw-r--r--sound/pci/lola/lola.h4
-rw-r--r--sound/pci/lola/lola_pcm.c49
2 files changed, 46 insertions, 7 deletions
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index bc8110ff6b46..180c2c124620 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -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;
 
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 4bb5b5bd6371..6be6b7e8f567 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -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);