/* 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; }
/* 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; }
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; }
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; }