Esempio n. 1
0
static int lola_pcm_open(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_pcm *pcm = lola_get_pcm(substream);
	struct lola_stream *str = lola_get_stream(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;

	mutex_lock(&chip->open_mutex);
	if (str->opened) {
		mutex_unlock(&chip->open_mutex);
		return -EBUSY;
	}
	str->substream = substream;
	str->master = NULL;
	str->opened = 1;
	runtime->hw = lola_pcm_hw;
	runtime->hw.channels_max = pcm->num_streams - str->index;
	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)*/
	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,
				   chip->granularity);
	mutex_unlock(&chip->open_mutex);
	return 0;
}
Esempio n. 2
0
/* 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)
{
	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;
}
Esempio n. 3
0
static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_stream *str = lola_get_stream(substream);
	unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB);

	if (pos >= str->bufsize)
		pos = 0;
	return bytes_to_frames(substream->runtime, pos);
}
Esempio n. 4
0
static int lola_pcm_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *hw_params)
{
	struct lola_stream *str = lola_get_stream(substream);

	str->bufsize = 0;
	str->period_bytes = 0;
	str->format_verb = 0;
	return snd_pcm_lib_malloc_pages(substream,
					params_buffer_bytes(hw_params));
}
Esempio n. 5
0
static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_pcm *pcm = lola_get_pcm(substream);
	struct lola_stream *str = lola_get_stream(substream);

	mutex_lock(&chip->open_mutex);
	lola_stream_reset(chip, str);
	lola_cleanup_slave_streams(pcm, str);
	mutex_unlock(&chip->open_mutex);
	return snd_pcm_lib_free_pages(substream);
}
Esempio n. 6
0
static int lola_pcm_prepare(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_pcm *pcm = lola_get_pcm(substream);
	struct lola_stream *str = lola_get_stream(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int bufsize, period_bytes, format_verb;
	int i, err;

	mutex_lock(&chip->open_mutex);
	lola_stream_reset(chip, str);
	lola_cleanup_slave_streams(pcm, str);
	if (str->index + runtime->channels > pcm->num_streams) {
		mutex_unlock(&chip->open_mutex);
		return -EINVAL;
	}
	for (i = 1; i < runtime->channels; i++) {
		str[i].master = str;
		str[i].opened = 1;
	}
	mutex_unlock(&chip->open_mutex);

	bufsize = snd_pcm_lib_buffer_bytes(substream);
	period_bytes = snd_pcm_lib_period_bytes(substream);
	format_verb = lola_get_format_verb(substream);

	str->bufsize = bufsize;
	str->period_bytes = period_bytes;
	str->format_verb = format_verb;

	err = lola_setup_periods(chip, pcm, substream, str);
	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;

	err = lola_setup_controller(chip, pcm, str);
	if (err < 0) {
		lola_stream_reset(chip, str);
		return err;
	}

	return 0;
}
Esempio n. 7
0
static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_stream *str;
	struct snd_pcm_substream *s;
	unsigned int start;
	unsigned int tstamp;
	bool sync_streams;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_RESUME:
		start = 1;
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_STOP:
		start = 0;
		break;
	default:
		return -EINVAL;
	}

	/*
	 * 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)
			continue;
		str = lola_get_stream(s);
		if (start)
			lola_stream_start(chip, str, tstamp);
		else
			lola_stream_stop(chip, str, tstamp);
		str->running = start;
		str->paused = !start;
		snd_pcm_trigger_done(s, substream);
	}
	spin_unlock(&chip->reg_lock);
	return 0;
}
Esempio n. 8
0
static int lola_pcm_close(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_stream *str = lola_get_stream(substream);

	mutex_lock(&chip->open_mutex);
	if (str->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;
}
Esempio n. 9
0
/* 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);
	}
	lola_sync_wait_for_fifo(chip, substream, true);
}
Esempio n. 10
0
static int lola_pcm_close(struct snd_pcm_substream *substream)
{
	struct lola *chip = snd_pcm_substream_chip(substream);
	struct lola_stream *str = lola_get_stream(substream);

	mutex_l