diff options
Diffstat (limited to 'sound/core/init.c')
| -rw-r--r-- | sound/core/init.c | 248 | 
1 files changed, 121 insertions, 127 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index 6b9087115da..7bdfd19e24a 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -28,6 +28,7 @@  #include <linux/time.h>  #include <linux/ctype.h>  #include <linux/pm.h> +#include <linux/completion.h>  #include <sound/core.h>  #include <sound/control.h> @@ -66,7 +67,7 @@ static int module_slot_match(struct module *module, int idx)  #ifdef MODULE  	const char *s1, *s2; -	if (!module || !module->name || !slots[idx]) +	if (!module || !*module->name || !slots[idx])  		return 0;  	s1 = module->name; @@ -94,7 +95,7 @@ static int module_slot_match(struct module *module, int idx)  	return match;  } -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS)  int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);  EXPORT_SYMBOL(snd_mixer_oss_notify_callback);  #endif @@ -112,11 +113,11 @@ static inline int init_info_for_card(struct snd_card *card)  	struct snd_info_entry *entry;  	if ((err = snd_info_card_register(card)) < 0) { -		snd_printd("unable to create card info\n"); +		dev_dbg(card->dev, "unable to create card info\n");  		return err;  	}  	if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) { -		snd_printd("unable to create card entry\n"); +		dev_dbg(card->dev, "unable to create card entry\n");  		return err;  	}  	entry->c.text.read = snd_card_id_read; @@ -131,8 +132,42 @@ static inline int init_info_for_card(struct snd_card *card)  #define init_info_for_card(card)  #endif +static int check_empty_slot(struct module *module, int slot) +{ +	return !slots[slot] || !*slots[slot]; +} + +/* return an empty slot number (>= 0) found in the given bitmask @mask. + * @mask == -1 == 0xffffffff means: take any free slot up to 32 + * when no slot is available, return the original @mask as is. + */ +static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int), +				 struct module *module) +{ +	int slot; + +	for (slot = 0; slot < SNDRV_CARDS; slot++) { +		if (slot < 32 && !(mask & (1U << slot))) +			continue; +		if (!test_bit(slot, snd_cards_lock)) { +			if (check(module, slot)) +				return slot; /* found */ +		} +	} +	return mask; /* unchanged */ +} + +static int snd_card_do_free(struct snd_card *card); +static const struct attribute_group *card_dev_attr_groups[]; + +static void release_card_device(struct device *dev) +{ +	snd_card_do_free(dev_to_snd_card(dev)); +} +  /** - *  snd_card_create - create and initialize a soundcard structure + *  snd_card_new - create and initialize a soundcard structure + *  @parent: the parent device object   *  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]   *  @xid: card identification (ASCII string)   *  @module: top level module for locking @@ -147,12 +182,12 @@ static inline int init_info_for_card(struct snd_card *card)   *   *  Return: Zero if successful or a negative error code.   */ -int snd_card_create(int idx, const char *xid, +int snd_card_new(struct device *parent, int idx, const char *xid,  		    struct module *module, int extra_size,  		    struct snd_card **card_ret)  {  	struct snd_card *card; -	int err, idx2; +	int err;  	if (snd_BUG_ON(!card_ret))  		return -EINVAL; @@ -163,36 +198,16 @@ int snd_card_create(int idx, const char *xid,  	card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);  	if (!card)  		return -ENOMEM; +	if (extra_size > 0) +		card->private_data = (char *)card + sizeof(struct snd_card);  	if (xid)  		strlcpy(card->id, xid, sizeof(card->id));  	err = 0;  	mutex_lock(&snd_card_mutex); -	if (idx < 0) { -		for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) { -			/* idx == -1 == 0xffff means: take any free slot */ -			if (idx2 < sizeof(int) && !(idx & (1U << idx2))) -				continue; -			if (!test_bit(idx2, snd_cards_lock)) { -				if (module_slot_match(module, idx2)) { -					idx = idx2; -					break; -				} -			} -		} -	} -	if (idx < 0) { -		for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) { -			/* idx == -1 == 0xffff means: take any free slot */ -			if (idx2 < sizeof(int) && !(idx & (1U << idx2))) -				continue; -			if (!test_bit(idx2, snd_cards_lock)) { -				if (!slots[idx2] || !*slots[idx2]) { -					idx = idx2; -					break; -				} -			} -		} -	} +	if (idx < 0) /* first check the matching module-name slot */ +		idx = get_slot_from_bitmask(idx, module_slot_match, module); +	if (idx < 0) /* if not matched, assign an empty slot */ +		idx = get_slot_from_bitmask(idx, check_empty_slot, module);  	if (idx < 0)  		err = -ENODEV;  	else if (idx < snd_ecards_limit) { @@ -202,53 +217,62 @@ int snd_card_create(int idx, const char *xid,  		err = -ENODEV;  	if (err < 0) {  		mutex_unlock(&snd_card_mutex); -		snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", +		dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",  			 idx, snd_ecards_limit - 1, err); -		goto __error; +		kfree(card); +		return err;  	}  	set_bit(idx, snd_cards_lock);		/* lock it */  	if (idx >= snd_ecards_limit)  		snd_ecards_limit = idx + 1; /* increase the limit */  	mutex_unlock(&snd_card_mutex); +	card->dev = parent;  	card->number = idx;  	card->module = module;  	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);  	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);  #endif + +	device_initialize(&card->card_dev); +	card->card_dev.parent = parent; +	card->card_dev.class = sound_class; +	card->card_dev.release = release_card_device; +	card->card_dev.groups = card_dev_attr_groups; +	err = kobject_set_name(&card->card_dev.kobj, "card%d", idx); +	if (err < 0) +		goto __error; +  	/* the control interface cannot be accessed from the user space until */  	/* snd_cards_bitmask and snd_cards are set with snd_card_register */  	err = snd_ctl_create(card);  	if (err < 0) { -		snd_printk(KERN_ERR "unable to register control minors\n"); +		dev_err(parent, "unable to register control minors\n");  		goto __error;  	}  	err = snd_info_card_create(card);  	if (err < 0) { -		snd_printk(KERN_ERR "unable to create card info\n"); +		dev_err(parent, "unable to create card info\n");  		goto __error_ctl;  	} -	if (extra_size > 0) -		card->private_data = (char *)card + sizeof(struct snd_card);  	*card_ret = card;  	return 0;        __error_ctl: -	snd_device_free_all(card, SNDRV_DEV_CMD_PRE); +	snd_device_free_all(card);        __error: -	kfree(card); +	put_device(&card->card_dev);    	return err;  } -EXPORT_SYMBOL(snd_card_create); +EXPORT_SYMBOL(snd_card_new);  /* return non-zero if a card is already locked */  int snd_card_locked(int card) @@ -391,7 +415,7 @@ int snd_card_disconnect(struct snd_card *card)  	/* phase 3: notify all connected devices about disconnection */  	/* at this point, they cannot respond to any calls except release() */ -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS)  	if (snd_mixer_oss_notify_callback)  		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);  #endif @@ -399,12 +423,12 @@ int snd_card_disconnect(struct snd_card *card)  	/* notify all devices that we are disconnected */  	err = snd_device_disconnect_all(card);  	if (err < 0) -		snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); +		dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);  	snd_info_card_disconnect(card); -	if (card->card_dev) { -		device_unregister(card->card_dev); -		card->card_dev = NULL; +	if (card->registered) { +		device_del(&card->card_dev); +		card->registered = false;  	}  #ifdef CONFIG_PM  	wake_up(&card->power_sleep); @@ -427,81 +451,48 @@ EXPORT_SYMBOL(snd_card_disconnect);   */  static int snd_card_do_free(struct snd_card *card)  { -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS)  	if (snd_mixer_oss_notify_callback)  		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);  #endif -	if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) { -		snd_printk(KERN_ERR "unable to free all devices (pre)\n"); -		/* Fatal, but this situation should never occur */ -	} -	if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) { -		snd_printk(KERN_ERR "unable to free all devices (normal)\n"); -		/* Fatal, but this situation should never occur */ -	} -	if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) { -		snd_printk(KERN_ERR "unable to free all devices (post)\n"); -		/* Fatal, but this situation should never occur */ -	} +	snd_device_free_all(card);  	if (card->private_free)  		card->private_free(card);  	snd_info_free_entry(card->proc_id);  	if (snd_info_card_free(card) < 0) { -		snd_printk(KERN_WARNING "unable to free card info\n"); +		dev_warn(card->dev, "unable to free card info\n");  		/* Not fatal error */  	} +	if (card->release_completion) +		complete(card->release_completion);  	kfree(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 ret; - -	atomic_inc(&card->refcount); -	ret = snd_card_disconnect(card); -	if (ret) { -		atomic_dec(&card->refcount); +	int ret = snd_card_disconnect(card); +	if (ret)  		return ret; -	} - -	card->free_on_last_close = 1; -	if (atomic_dec_and_test(&card->refcount)) -		snd_card_do_free(card); +	put_device(&card->card_dev);  	return 0;  } -  EXPORT_SYMBOL(snd_card_free_when_closed);  int snd_card_free(struct snd_card *card)  { -	int ret = snd_card_disconnect(card); +	struct completion released; +	int ret; + +	init_completion(&released); +	card->release_completion = &released; +	ret = snd_card_free_when_closed(card);  	if (ret)  		return ret; -  	/* wait, until all devices are ready for the free operation */ -	wait_event(card->shutdown_sleep, !atomic_read(&card->refcount)); -	snd_card_do_free(card); +	wait_for_completion(&released);  	return 0;  } -  EXPORT_SYMBOL(snd_card_free);  /* retrieve the last word of shortname or longname */ @@ -595,9 +586,9 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,  		goto again;  	}  	/* last resort... */ -	snd_printk(KERN_ERR "unable to set card id (%s)\n", id); +	dev_err(card->dev, "unable to set card id (%s)\n", id);  	if (card->proc_root->name) -		strcpy(card->id, card->proc_root->name); +		strlcpy(card->id, card->proc_root->name, sizeof(card->id));  }  /** @@ -623,15 +614,15 @@ static ssize_t  card_id_show_attr(struct device *dev,  		  struct device_attribute *attr, char *buf)  { -	struct snd_card *card = dev_get_drvdata(dev); -	return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)"); +	struct snd_card *card = container_of(dev, struct snd_card, card_dev); +	return snprintf(buf, PAGE_SIZE, "%s\n", card->id);  }  static ssize_t  card_id_store_attr(struct device *dev, struct device_attribute *attr,  		   const char *buf, size_t count)  { -	struct snd_card *card = dev_get_drvdata(dev); +	struct snd_card *card = container_of(dev, struct snd_card, card_dev);  	char buf1[sizeof(card->id)];  	size_t copy = count > sizeof(card->id) - 1 ?  					sizeof(card->id) - 1 : count; @@ -657,19 +648,32 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,  	return count;  } -static struct device_attribute card_id_attrs = -	__ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr); +static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);  static ssize_t  card_number_show_attr(struct device *dev,  		     struct device_attribute *attr, char *buf)  { -	struct snd_card *card = dev_get_drvdata(dev); -	return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1); +	struct snd_card *card = container_of(dev, struct snd_card, card_dev); +	return snprintf(buf, PAGE_SIZE, "%i\n", card->number);  } -static struct device_attribute card_number_attrs = -	__ATTR(number, S_IRUGO, card_number_show_attr, NULL); +static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL); + +static struct attribute *card_dev_attrs[] = { +	&dev_attr_id.attr, +	&dev_attr_number.attr, +	NULL +}; + +static struct attribute_group card_dev_attr_group = { +	.attrs	= card_dev_attrs, +}; + +static const struct attribute_group *card_dev_attr_groups[] = { +	&card_dev_attr_group, +	NULL +};  /**   *  snd_card_register - register the soundcard @@ -689,12 +693,11 @@ int snd_card_register(struct snd_card *card)  	if (snd_BUG_ON(!card))  		return -EINVAL; -	if (!card->card_dev) { -		card->card_dev = device_create(sound_class, card->dev, -					       MKDEV(0, 0), card, -					       "card%i", card->number); -		if (IS_ERR(card->card_dev)) -			card->card_dev = NULL; +	if (!card->registered) { +		err = device_add(&card->card_dev); +		if (err < 0) +			return err; +		card->registered = true;  	}  	if ((err = snd_device_register_all(card)) < 0) @@ -720,19 +723,10 @@ int snd_card_register(struct snd_card *card)  	snd_cards[card->number] = card;  	mutex_unlock(&snd_card_mutex);  	init_info_for_card(card); -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS)  	if (snd_mixer_oss_notify_callback)  		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);  #endif -	if (card->card_dev) { -		err = device_create_file(card->card_dev, &card_id_attrs); -		if (err < 0) -			return err; -		err = device_create_file(card->card_dev, &card_number_attrs); -		if (err < 0) -			return err; -	} -  	return 0;  } @@ -905,7 +899,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); +	get_device(&card->card_dev);  	spin_unlock(&card->files_lock);  	return 0;  } @@ -944,11 +938,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)  	}  	spin_unlock(&card->files_lock);  	if (!found) { -		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); +		dev_err(card->dev, "card file remove problem (%p)\n", file);  		return -ENOENT;  	}  	kfree(found); -	snd_card_unref(card); +	put_device(&card->card_dev);  	return 0;  }  | 
