/* hw_params callback */
static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
				     struct snd_pcm_hw_params *params)
{
	int err;
	struct snd_pcm_runtime *runtime = substream->runtime;
	bcm2835_alsa_stream_t *alsa_stream =
	    (bcm2835_alsa_stream_t *) runtime->private_data;

	audio_info(" .. IN\n");

	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
	if (err < 0) {
		audio_error
		    (" pcm_lib_malloc failed to allocated pages for buffers\n");
		return err;
	}

	err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
				       params_rate(params),
				       snd_pcm_format_width(params_format
							    (params)));
	if (err < 0) {
		audio_error(" error setting hw params\n");
	}

	bcm2835_audio_setup(alsa_stream);

	/* in preparation of the stream, set the controls (volume level) of the stream */
	bcm2835_audio_set_ctls(alsa_stream->chip);

	audio_info(" .. OUT\n");

	return err;
}
Exemple #2
0
/* prepare callback */
static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
{
	struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
	int channels;
	int err;

	audio_info(" .. IN\n");

	if (mutex_lock_interruptible(&chip->audio_mutex))
		return -EINTR;

	/* notify the vchiq that it should enter spdif passthrough mode by
	 * setting channels=0 (see
	 * https://github.com/raspberrypi/linux/issues/528) */
	if (chip->spdif_status & IEC958_AES0_NONAUDIO)
		channels = 0;
	else
		channels = alsa_stream->channels;

	err = bcm2835_audio_set_params(alsa_stream, channels,
		alsa_stream->params_rate,
		alsa_stream->pcm_format_width);
	if (err < 0) {
		audio_error(" error setting hw params\n");
	}

	bcm2835_audio_setup(alsa_stream);

	/* in preparation of the stream, set the controls (volume level) of the stream */
	bcm2835_audio_set_ctls(alsa_stream->chip);


	memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));

	alsa_stream->pcm_indirect.hw_buffer_size =
		alsa_stream->pcm_indirect.sw_buffer_size =
		snd_pcm_lib_buffer_bytes(substream);

	alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
	alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
	alsa_stream->pos = 0;

	audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
		alsa_stream->buffer_size, alsa_stream->period_size,
		alsa_stream->pos, runtime->frame_bits);

	mutex_unlock(&chip->audio_mutex);
	audio_info(" .. OUT\n");
	return 0;
}
Exemple #3
0
static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
{
	int i, err = 0;

	/* change ctls for all substreams */
	for (i = 0; i < MAX_SUBSTREAMS; i++) {
		if (chip->alsa_stream[i]) {
			err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
			if (err < 0)
				break;
		}
	}
	return err;
}
static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
	int changed = 0;

	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
		if (chip->mute) {
			chip->mute = 0;
			changed = 1;
		}
		if (changed
		    || (ucontrol->value.integer.value[0] != chip->volume)) {
			int atten;

			chip->volume = ucontrol->value.integer.value[0];
			changed = 1;
			atten = -((chip->volume << 8) / 100);
			chip->volume = atten;
		}

	} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
		/* Not implemented */
		if (ucontrol->value.integer.value[0] != chip->mute) {
			chip->mute = ucontrol->value.integer.value[0];
			changed = 0;
		}
	} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
		if (ucontrol->value.integer.value[0] != chip->dest) {
			chip->dest = ucontrol->value.integer.value[0];
			changed = 1;
		}
	}

	if (changed) {
		if (bcm2835_audio_set_ctls(chip))
			printk(KERN_ERR "Failed to set ALSA controls..\n");
	}

	return changed;
}
Exemple #5
0
static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
	int changed = 0;

	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
		audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
		if (chip->mute == CTRL_VOL_MUTE) {
			/* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
			return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
		}
		if (changed
		    || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {

			chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
			changed = 1;
		}

	} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
		/* Now implemented */
		audio_info(" Mute attempted\n");
		changed = toggle_mute(chip, ucontrol->value.integer.value[0]);

	} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
		if (ucontrol->value.integer.value[0] != chip->dest) {
			chip->dest = ucontrol->value.integer.value[0];
			changed = 1;
		}
	}

	if (changed) {
		if (bcm2835_audio_set_ctls(chip))
			printk(KERN_ERR "Failed to set ALSA controls..\n");
	}

	return changed;
}