cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/bcm2835-audio/bcm2835-ctl.c

/*****************************************************************************
 * Copyright 2011 Broadcom Corporation.  All rights reserved.
 *
 * Unless you and Broadcom execute a separate written software license
 * agreement governing use of this software, this software is licensed to you
 * under the terms of the GNU General Public License version 2, available at
 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
 *
 * Notwithstanding the above, under no circumstances may you combine this
 * software in any way with any other Broadcom software provided under a
 * license other than the GPL, without Broadcom's express prior written
 * consent.
 *****************************************************************************/

#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>

#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/asoundef.h>

#include "bcm2835.h"

/* volume maximum and minimum in terms of 0.01dB */

#define CTRL_VOL_MAX 400

#define CTRL_VOL_MIN -10239 
/* originally -10240 */


static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { audio_info(" ... IN\n"); if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = CTRL_VOL_MIN; uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = AUDIO_DEST_MAX - 1; } audio_info(" ... OUT\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran160100.00%1100.00%
Total160100.00%1100.00%

/* toggles mute on or off depending on the value of nmute, and returns * 1 if the mute value was changed, otherwise 0 */
static int toggle_mute(struct bcm2835_chip *chip, int nmute) { /* if settings are ok, just return 0 */ if (chip->mute == nmute) return 0; /* if the sound is muted then we need to unmute */ if (chip->mute == CTRL_VOL_MUTE) { chip->volume = chip->old_volume; /* copy the old volume back */ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); } else /* otherwise we mute */ { chip->old_volume = chip->volume; chip->volume = 26214; /* set volume to minimum level AKA mute */ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); } chip->mute = nmute; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran100100.00%1100.00%
Total100100.00%1100.00%


static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK)); if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) ucontrol->value.integer.value[0] = chip2alsa(chip->volume); else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) ucontrol->value.integer.value[0] = chip->mute; else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) ucontrol->value.integer.value[0] = chip->dest; mutex_unlock(&chip->audio_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran140100.00%1100.00%
Total140100.00%1100.00%


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 (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; 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); */ changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */ goto unlock; } 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"); } unlock: mutex_unlock(&chip->audio_mutex); return changed; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran261100.00%1100.00%
Total261100.00%1100.00%

static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1); static struct snd_kcontrol_new snd_bcm2835_ctl[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .private_value = PCM_PLAYBACK_VOLUME, .info = snd_bcm2835_ctl_info, .get = snd_bcm2835_ctl_get, .put = snd_bcm2835_ctl_put, .count = 1, .tlv = {.p = snd_bcm2835_db_scale} }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .private_value = PCM_PLAYBACK_MUTE, .info = snd_bcm2835_ctl_info, .get = snd_bcm2835_ctl_get, .put = snd_bcm2835_ctl_put, .count = 1, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Route", .index = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .private_value = PCM_PLAYBACK_DEVICE, .info = snd_bcm2835_ctl_info, .get = snd_bcm2835_ctl_get, .put = snd_bcm2835_ctl_put, .count = 1, }, };
static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran31100.00%1100.00%
Total31100.00%1100.00%


static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); int i; if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (chip->spdif_status >> (i * 8)) & 0xff; mutex_unlock(&chip->audio_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran9198.91%150.00%
Dan Carpenter11.09%150.00%
Total92100.00%2100.00%


static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); unsigned int val = 0; int i, change; if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; for (i = 0; i < 4; i++) val |= (unsigned int) ucontrol->value.iec958.status[i] << (i * 8); change = val != chip->spdif_status; chip->spdif_status = val; mutex_unlock(&chip->audio_mutex); return change; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran112100.00%1100.00%
Total112100.00%1100.00%


static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran31100.00%1100.00%
Total31100.00%1100.00%


static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* bcm2835 supports only consumer mode and sets all other format flags * automatically. So the only thing left is signalling non-audio * content */ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran33100.00%1100.00%
Total33100.00%1100.00%


static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran31100.00%1100.00%
Total31100.00%1100.00%


static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); int i; if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (chip->spdif_status >> (i * 8)) & 0xff; mutex_unlock(&chip->audio_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran92100.00%1100.00%
Total92100.00%1100.00%


static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); unsigned int val = 0; int i, change; if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; for (i = 0; i < 4; i++) val |= (unsigned int) ucontrol->value.iec958.status[i] << (i * 8); change = val != chip->spdif_status; chip->spdif_status = val; mutex_unlock(&chip->audio_mutex); return change; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran112100.00%1100.00%
Total112100.00%1100.00%

static struct snd_kcontrol_new snd_bcm2835_spdif[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), .info = snd_bcm2835_spdif_default_info, .get = snd_bcm2835_spdif_default_get, .put = snd_bcm2835_spdif_default_put }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), .info = snd_bcm2835_spdif_mask_info, .get = snd_bcm2835_spdif_mask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), .info = snd_bcm2835_spdif_stream_info, .get = snd_bcm2835_spdif_stream_get, .put = snd_bcm2835_spdif_stream_put, }, };
int snd_bcm2835_new_ctl(struct bcm2835_chip *chip) { int err; unsigned int idx; strcpy(chip->card->mixername, "Broadcom Mixer"); for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) { err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_bcm2835_ctl[idx], chip)); if (err < 0) return err; } for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) { err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_bcm2835_spdif[idx], chip)); if (err < 0) return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran125100.00%1100.00%
Total125100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Michael Zoran167899.94%150.00%
Dan Carpenter10.06%150.00%
Total1679100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.