Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef61076 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sound fixes from Takashi Iwai:
 "The significant part here is a few security fixes for ALSA core
  control API by Lars.  Besides that, there are a few fixes for ASoC
  sigmadsp (again by Lars) for building properly, and small fixes for
  ASoC rsnd, MMP, PXA and FSL, in addition to a fix for bogus WARNING in
  i915/HD-audio binding"

* tag 'sound-3.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: control: Make sure that id->index does not overflow
  ALSA: control: Handle numid overflow
  ALSA: control: Don't access controls outside of protected regions
  ALSA: control: Fix replacing user controls
  ALSA: control: Protect user controls against concurrent access
  drm/i915, HD-audio: Don't continue probing when nomodeset is given
  ASoC: fsl: Fix build problem
  ASoC: rsnd: fixup index of src/dst mod when capture
  ASoC: fsl_spdif: Fix integer overflow when calculating divisors
  ASoC: fsl_spdif: Fix incorrect usage of regmap_read()
  ASoC: dapm: Make sure register value is in sync with DAPM kcontrol state
  ASoC: sigmadsp: Split regmap and I2C support into separate modules
  ASoC: MMP audio needs sram support
  ASoC: pxa: add I2C dependencies as needed
parents 0c9bc275 8d42fda9
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -6019,30 +6019,32 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
static struct i915_power_domains *hsw_pwr;

/* Display audio driver power well request */
void i915_request_power_well(void)
int i915_request_power_well(void)
{
	struct drm_i915_private *dev_priv;

	if (WARN_ON(!hsw_pwr))
		return;
	if (!hsw_pwr)
		return -ENODEV;

	dev_priv = container_of(hsw_pwr, struct drm_i915_private,
				power_domains);
	intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
	return 0;
}
EXPORT_SYMBOL_GPL(i915_request_power_well);

/* Display audio driver power well release */
void i915_release_power_well(void)
int i915_release_power_well(void)
{
	struct drm_i915_private *dev_priv;

	if (WARN_ON(!hsw_pwr))
		return;
	if (!hsw_pwr)
		return -ENODEV;

	dev_priv = container_of(hsw_pwr, struct drm_i915_private,
				power_domains);
	intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
	return 0;
}
EXPORT_SYMBOL_GPL(i915_release_power_well);

+2 −2
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
#define _I915_POWERWELL_H_

/* For use by hda_i915 driver */
extern void i915_request_power_well(void);
extern void i915_release_power_well(void);
extern int i915_request_power_well(void);
extern int i915_release_power_well(void);

#endif				/* _I915_POWERWELL_H_ */
+2 −0
Original line number Diff line number Diff line
@@ -116,6 +116,8 @@ struct snd_card {
	int user_ctl_count;		/* count of all user controls */
	struct list_head controls;	/* all controls for this card */
	struct list_head ctl_files;	/* active control files */
	struct mutex user_ctl_lock;	/* protects user controls against
					   concurrent access */

	struct snd_info_entry *proc_root;	/* root for soundcard specific files */
	struct snd_info_entry *proc_id;	/* the card id */
+51 −27
Original line number Diff line number Diff line
@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
{
	struct snd_kcontrol *kctl;

	/* Make sure that the ids assigned to the control do not wrap around */
	if (card->last_numid >= UINT_MAX - count)
		card->last_numid = 0;

	list_for_each_entry(kctl, &card->controls, list) {
		if (kctl->id.numid < card->last_numid + 1 + count &&
		    kctl->id.numid + kctl->count > card->last_numid + 1) {
@@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
	struct snd_ctl_elem_id id;
	unsigned int idx;
	unsigned int count;
	int err = -EINVAL;

	if (! kcontrol)
@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
	if (snd_BUG_ON(!card || !kcontrol->info))
		goto error;
	id = kcontrol->id;
	if (id.index > UINT_MAX - kcontrol->count)
		goto error;

	down_write(&card->controls_rwsem);
	if (snd_ctl_find_id(card, &id)) {
		up_write(&card->controls_rwsem);
@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
	card->controls_count += kcontrol->count;
	kcontrol->id.numid = card->last_numid + 1;
	card->last_numid += kcontrol->count;
	count = kcontrol->count;
	up_write(&card->controls_rwsem);
	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
	for (idx = 0; idx < count; idx++, id.index++, id.numid++)
		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
	return 0;

@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
		    bool add_on_replace)
{
	struct snd_ctl_elem_id id;
	unsigned int count;
	unsigned int idx;
	struct snd_kcontrol *old;
	int ret;
@@ -423,8 +433,9 @@ add:
	card->controls_count += kcontrol->count;
	kcontrol->id.numid = card->last_numid + 1;
	card->last_numid += kcontrol->count;
	count = kcontrol->count;
	up_write(&card->controls_rwsem);
	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
	for (idx = 0; idx < count; idx++, id.index++, id.numid++)
		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
	return 0;

@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
			result = kctl->put(kctl, control);
		}
		if (result > 0) {
			struct snd_ctl_elem_id id = control->id;
			up_read(&card->controls_rwsem);
			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
				       &control->id);
			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
			return 0;
		}
	}
@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,

struct user_element {
	struct snd_ctl_elem_info info;
	struct snd_card *card;
	void *elem_data;		/* element data */
	unsigned long elem_data_size;	/* size of element data in bytes */
	void *tlv_data;			/* TLV data */
@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
{
	struct user_element *ue = kcontrol->private_data;

	mutex_lock(&ue->card->user_ctl_lock);
	memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
	mutex_unlock(&ue->card->user_ctl_lock);
	return 0;
}

@@ -1044,9 +1058,11 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
	int change;
	struct user_element *ue = kcontrol->private_data;

	mutex_lock(&ue->card->user_ctl_lock);
	change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
	if (change)
		memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
	mutex_unlock(&ue->card->user_ctl_lock);
	return change;
}

@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
		new_data = memdup_user(tlv, size);
		if (IS_ERR(new_data))
			return PTR_ERR(new_data);
		mutex_lock(&ue->card->user_ctl_lock);
		change = ue->tlv_data_size != size;
		if (!change)
			change = memcmp(ue->tlv_data, new_data, size);
		kfree(ue->tlv_data);
		ue->tlv_data = new_data;
		ue->tlv_data_size = size;
		mutex_unlock(&ue->card->user_ctl_lock);
	} else {
		if (! ue->tlv_data_size || ! ue->tlv_data)
			return -ENXIO;
		if (size < ue->tlv_data_size)
			return -ENOSPC;
		int ret = 0;

		mutex_lock(&ue->card->user_ctl_lock);
		if (!ue->tlv_data_size || !ue->tlv_data) {
			ret = -ENXIO;
			goto err_unlock;
		}
		if (size < ue->tlv_data_size) {
			ret = -ENOSPC;
			goto err_unlock;
		}
		if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
			return -EFAULT;
			ret = -EFAULT;
err_unlock:
		mutex_unlock(&ue->card->user_ctl_lock);
		if (ret)
			return ret;
	}
	return change;
}
@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
	struct user_element *ue;
	int idx, err;

	if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
		return -ENOMEM;
	if (info->count < 1)
		return -EINVAL;
	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
				 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
	info->id.numid = 0;
	memset(&kctl, 0, sizeof(kctl));
	down_write(&card->controls_rwsem);
	_kctl = snd_ctl_find_id(card, &info->id);
	err = 0;
	if (_kctl) {
		if (replace)
			err = snd_ctl_remove(card, _kctl);
		else
			err = -EBUSY;
	} else {
		if (replace)
			err = -ENOENT;
	}
	up_write(&card->controls_rwsem);
	if (err < 0)

	if (replace) {
		err = snd_ctl_remove_user_ctl(file, &info->id);
		if (err)
			return err;
	}

	if (card->user_ctl_count >= MAX_USER_CONTROLS)
		return -ENOMEM;

	memcpy(&kctl.id, &info->id, sizeof(info->id));
	kctl.count = info->owner ? info->owner : 1;
	access |= SNDRV_CTL_ELEM_ACCESS_USER;
@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
	ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
	if (ue == NULL)
		return -ENOMEM;
	ue->card = card;
	ue->info = *info;
	ue->info.access = 0;
	ue->elem_data = (char *)ue + sizeof(*ue);
@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
		}
		err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
		if (err > 0) {
			struct snd_ctl_elem_id id = kctl->id;
			up_read(&card->controls_rwsem);
			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
			return 0;
		}
	} else {
+1 −0
Original line number Diff line number Diff line
@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
	INIT_LIST_HEAD(&card->devices);
	init_rwsem(&card->controls_rwsem);
	rwlock_init(&card->ctl_files_rwlock);
	mutex_init(&card->user_ctl_lock);
	INIT_LIST_HEAD(&card->controls);
	INIT_LIST_HEAD(&card->ctl_files);
	spin_lock_init(&card->files_lock);
Loading