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

Commit 33046957 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sound fixes from Takashi Iwai:
 "This contains unexpectedly many changes in a wide range due to the
  fixes for races at disconnection of USB audio devices.  In the end, we
  end up covering fairly core parts of sound subsystem.

  Other than that, just a few usual small fixes."

* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: ice1724: Fix rate setup after resume
  ALSA: Avoid endless sleep after disconnect
  ALSA: Add a reference counter to card instance
  ALSA: usb-audio: Fix races at disconnection in mixer_quirks.c
  ALSA: usb-audio: Use rwsem for disconnect protection
  ALSA: usb-audio: Fix races at disconnection
  ALSA: PCM: Fix some races at disconnection
  ASoC: omap-dmic: Correct functional clock name
  ASoC: zoom2: Fix compile error by including correct header files
  ALSA: hda - Fix mute-LED setup for HP dv5 laptop
parents 08f05c49 16c2e1fa
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ struct snd_card {
	int shutdown;			/* this card is going down */
	int free_on_last_close;		/* free in context of file_release */
	wait_queue_head_t shutdown_sleep;
	atomic_t refcount;		/* refcount for disconnection */
	struct device *dev;		/* device assigned to this card */
	struct device *card_dev;	/* cardX object for sysfs */

@@ -189,6 +190,7 @@ struct snd_minor {
	const struct file_operations *f_ops;	/* file operations */
	void *private_data;		/* private data for f_ops->open */
	struct device *dev;		/* device for sysfs */
	struct snd_card *card_ptr;	/* assigned card instance */
};

/* return a device pointer linked to each sound device as a parent */
@@ -295,6 +297,7 @@ int snd_card_info_done(void);
int snd_component_add(struct snd_card *card, const char *component);
int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
void snd_card_unref(struct snd_card *card);

#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))

+7 −2
Original line number Diff line number Diff line
@@ -100,12 +100,15 @@ static int snd_compr_open(struct inode *inode, struct file *f)

	if (dirn != compr->direction) {
		pr_err("this device doesn't support this direction\n");
		snd_card_unref(compr->card);
		return -EINVAL;
	}

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
	if (!data) {
		snd_card_unref(compr->card);
		return -ENOMEM;
	}
	data->stream.ops = compr->ops;
	data->stream.direction = dirn;
	data->stream.private_data = compr->private_data;
@@ -113,6 +116,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
	if (!runtime) {
		kfree(data);
		snd_card_unref(compr->card);
		return -ENOMEM;
	}
	runtime->state = SNDRV_PCM_STATE_OPEN;
@@ -126,7 +130,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
		kfree(runtime);
		kfree(data);
	}
	return ret;
	snd_card_unref(compr->card);
	return 0;
}

static int snd_compr_free(struct inode *inode, struct file *f)
+5 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
	write_lock_irqsave(&card->ctl_files_rwlock, flags);
	list_add_tail(&ctl->list, &card->ctl_files);
	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
	snd_card_unref(card);
	return 0;

      __error:
@@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
      __error2:
	snd_card_file_remove(card, file);
      __error1:
	if (card)
		snd_card_unref(card);
      	return err;
}

@@ -1434,6 +1437,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
			spin_unlock_irq(&ctl->read_lock);
			schedule();
			remove_wait_queue(&ctl->change_sleep, &wait);
			if (ctl->card->shutdown)
				return -ENODEV;
			if (signal_pending(current))
				return -ERESTARTSYS;
			spin_lock_irq(&ctl->read_lock);
+11 −1
Original line number Diff line number Diff line
@@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
	if (hw == NULL)
		return -ENODEV;

	if (!try_module_get(hw->card->module))
	if (!try_module_get(hw->card->module)) {
		snd_card_unref(hw->card);
		return -EFAULT;
	}

	init_waitqueue_entry(&wait, current);
	add_wait_queue(&hw->open_wait, &wait);
@@ -129,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
		mutex_unlock(&hw->open_mutex);
		schedule();
		mutex_lock(&hw->open_mutex);
		if (hw->card->shutdown) {
			err = -ENODEV;
			break;
		}
		if (signal_pending(current)) {
			err = -ERESTARTSYS;
			break;
@@ -148,6 +154,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
	mutex_unlock(&hw->open_mutex);
	if (err < 0)
		module_put(hw->card->module);
	snd_card_unref(hw->card);
	return err;
}

@@ -459,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
		mutex_unlock(&register_mutex);
		return -EINVAL;
	}
	mutex_lock(&hwdep->open_mutex);
	wake_up(&hwdep->open_wait);
#ifdef CONFIG_SND_OSSEMUL
	if (hwdep->ossreg)
		snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
	snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
	list_del_init(&hwdep->list);
	mutex_unlock(&hwdep->open_mutex);
	mutex_unlock(&register_mutex);
	return 0;
}
+30 −20
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
	spin_lock_init(&card->files_lock);
	INIT_LIST_HEAD(&card->files_list);
	init_waitqueue_head(&card->shutdown_sleep);
	atomic_set(&card->refcount, 0);
#ifdef CONFIG_PM
	mutex_init(&card->power_lock);
	init_waitqueue_head(&card->power_sleep);
@@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
	return 0;
}

/**
 * snd_card_unref - release the reference counter
 * @card: the card instance
 *
 * Decrements the reference counter.  When it reaches to zero, wake up
 * the sleeper and call the destructor if needed.
 */
void snd_card_unref(struct snd_card *card)
{
	if (atomic_dec_and_test(&card->refcount)) {
		wake_up(&card->shutdown_sleep);
		if (card->free_on_last_close)
			snd_card_do_free(card);
	}
}
EXPORT_SYMBOL(snd_card_unref);

int snd_card_free_when_closed(struct snd_card *card)
{
	int free_now = 0;
	int ret = snd_card_disconnect(card);
	if (ret)
	int ret;

	atomic_inc(&card->refcount);
	ret = snd_card_disconnect(card);
	if (ret) {
		atomic_dec(&card->refcount);
		return ret;
	}

	spin_lock(&card->files_lock);
	if (list_empty(&card->files_list))
		free_now = 1;
	else
	card->free_on_last_close = 1;
	spin_unlock(&card->files_lock);

	if (free_now)
	if (atomic_dec_and_test(&card->refcount))
		snd_card_do_free(card);
	return 0;
}
@@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
		return ret;

	/* wait, until all devices are ready for the free operation */
	wait_event(card->shutdown_sleep, list_empty(&card->files_list));
	wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
	snd_card_do_free(card);
	return 0;
}
@@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
		return -ENODEV;
	}
	list_add(&mfile->list, &card->files_list);
	atomic_inc(&card->refcount);
	spin_unlock(&card->files_lock);
	return 0;
}
@@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
int snd_card_file_remove(struct snd_card *card, struct file *file)
{
	struct snd_monitor_file *mfile, *found = NULL;
	int last_close = 0;

	spin_lock(&card->files_lock);
	list_for_each_entry(mfile, &card->files_list, list) {
@@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
			break;
		}
	}
	if (list_empty(&card->files_list))
		last_close = 1;
	spin_unlock(&card->files_lock);
	if (last_close) {
		wake_up(&card->shutdown_sleep);
		if (card->free_on_last_close)
			snd_card_do_free(card);
	}
	if (!found) {
		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
		return -ENOENT;
	}
	kfree(found);
	snd_card_unref(card);
	return 0;
}

Loading