diff options
Diffstat (limited to 'sound/core/device.c')
| -rw-r--r-- | sound/core/device.c | 175 | 
1 files changed, 77 insertions, 98 deletions
diff --git a/sound/core/device.c b/sound/core/device.c index df88defed17..41bec3075ae 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -41,29 +41,73 @@   *   * Return: Zero if successful, or a negative error code on failure.   */ -int snd_device_new(struct snd_card *card, snd_device_type_t type, +int snd_device_new(struct snd_card *card, enum snd_device_type type,  		   void *device_data, struct snd_device_ops *ops)  {  	struct snd_device *dev; +	struct list_head *p;  	if (snd_BUG_ON(!card || !device_data || !ops))  		return -ENXIO;  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);  	if (dev == NULL) { -		snd_printk(KERN_ERR "Cannot allocate device\n"); +		dev_err(card->dev, "Cannot allocate device, type=%d\n", type);  		return -ENOMEM;  	} +	INIT_LIST_HEAD(&dev->list);  	dev->card = card;  	dev->type = type;  	dev->state = SNDRV_DEV_BUILD;  	dev->device_data = device_data;  	dev->ops = ops; -	list_add(&dev->list, &card->devices);	/* add to the head of list */ + +	/* insert the entry in an incrementally sorted list */ +	list_for_each_prev(p, &card->devices) { +		struct snd_device *pdev = list_entry(p, struct snd_device, list); +		if ((unsigned int)pdev->type <= (unsigned int)type) +			break; +	} + +	list_add(&dev->list, p);  	return 0;  } -  EXPORT_SYMBOL(snd_device_new); +static int __snd_device_disconnect(struct snd_device *dev) +{ +	if (dev->state == SNDRV_DEV_REGISTERED) { +		if (dev->ops->dev_disconnect && +		    dev->ops->dev_disconnect(dev)) +			dev_err(dev->card->dev, "device disconnect failure\n"); +		dev->state = SNDRV_DEV_DISCONNECTED; +	} +	return 0; +} + +static void __snd_device_free(struct snd_device *dev) +{ +	/* unlink */ +	list_del(&dev->list); + +	__snd_device_disconnect(dev); +	if (dev->ops->dev_free) { +		if (dev->ops->dev_free(dev)) +			dev_err(dev->card->dev, "device free failure\n"); +	} +	kfree(dev); +} + +static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) +{ +	struct snd_device *dev; + +	list_for_each_entry(dev, &card->devices, list) +		if (dev->device_data == device_data) +			return dev; + +	return NULL; +} +  /**   * snd_device_free - release the device from the card   * @card: the card instance @@ -72,73 +116,33 @@ EXPORT_SYMBOL(snd_device_new);   * Removes the device from the list on the card and invokes the   * callbacks, dev_disconnect and dev_free, corresponding to the state.   * Then release the device. - * - * Return: Zero if successful, or a negative error code on failure or if the - * device not found.   */ -int snd_device_free(struct snd_card *card, void *device_data) +void snd_device_free(struct snd_card *card, void *device_data)  {  	struct snd_device *dev;  	if (snd_BUG_ON(!card || !device_data)) -		return -ENXIO; -	list_for_each_entry(dev, &card->devices, list) { -		if (dev->device_data != device_data) -			continue; -		/* unlink */ -		list_del(&dev->list); -		if (dev->state == SNDRV_DEV_REGISTERED && -		    dev->ops->dev_disconnect) -			if (dev->ops->dev_disconnect(dev)) -				snd_printk(KERN_ERR -					   "device disconnect failure\n"); -		if (dev->ops->dev_free) { -			if (dev->ops->dev_free(dev)) -				snd_printk(KERN_ERR "device free failure\n"); -		} -		kfree(dev); -		return 0; -	} -	snd_printd("device free %p (from %pF), not found\n", device_data, -		   __builtin_return_address(0)); -	return -ENXIO; +		return; +	dev = look_for_dev(card, device_data); +	if (dev) +		__snd_device_free(dev); +	else +		dev_dbg(card->dev, "device free %p (from %pF), not found\n", +			device_data, __builtin_return_address(0));  } -  EXPORT_SYMBOL(snd_device_free); -/** - * snd_device_disconnect - disconnect the device - * @card: the card instance - * @device_data: the data pointer to disconnect - * - * Turns the device into the disconnection state, invoking - * dev_disconnect callback, if the device was already registered. - * - * Usually called from snd_card_disconnect(). - * - * Return: Zero if successful, or a negative error code on failure or if the - * device not found. - */ -int snd_device_disconnect(struct snd_card *card, void *device_data) +static int __snd_device_register(struct snd_device *dev)  { -	struct snd_device *dev; - -	if (snd_BUG_ON(!card || !device_data)) -		return -ENXIO; -	list_for_each_entry(dev, &card->devices, list) { -		if (dev->device_data != device_data) -			continue; -		if (dev->state == SNDRV_DEV_REGISTERED && -		    dev->ops->dev_disconnect) { -			if (dev->ops->dev_disconnect(dev)) -				snd_printk(KERN_ERR "device disconnect failure\n"); -			dev->state = SNDRV_DEV_DISCONNECTED; +	if (dev->state == SNDRV_DEV_BUILD) { +		if (dev->ops->dev_register) { +			int err = dev->ops->dev_register(dev); +			if (err < 0) +				return err;  		} -		return 0; +		dev->state = SNDRV_DEV_REGISTERED;  	} -	snd_printd("device disconnect %p (from %pF), not found\n", device_data, -		   __builtin_return_address(0)); -	return -ENXIO; +	return 0;  }  /** @@ -157,26 +161,15 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)  int snd_device_register(struct snd_card *card, void *device_data)  {  	struct snd_device *dev; -	int err;  	if (snd_BUG_ON(!card || !device_data))  		return -ENXIO; -	list_for_each_entry(dev, &card->devices, list) { -		if (dev->device_data != device_data) -			continue; -		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { -			if ((err = dev->ops->dev_register(dev)) < 0) -				return err; -			dev->state = SNDRV_DEV_REGISTERED; -			return 0; -		} -		snd_printd("snd_device_register busy\n"); -		return -EBUSY; -	} +	dev = look_for_dev(card, device_data); +	if (dev) +		return __snd_device_register(dev);  	snd_BUG();  	return -ENXIO;  } -  EXPORT_SYMBOL(snd_device_register);  /* @@ -191,11 +184,9 @@ int snd_device_register_all(struct snd_card *card)  	if (snd_BUG_ON(!card))  		return -ENXIO;  	list_for_each_entry(dev, &card->devices, list) { -		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { -			if ((err = dev->ops->dev_register(dev)) < 0) -				return err; -			dev->state = SNDRV_DEV_REGISTERED; -		} +		err = __snd_device_register(dev); +		if (err < 0) +			return err;  	}  	return 0;  } @@ -211,8 +202,8 @@ int snd_device_disconnect_all(struct snd_card *card)  	if (snd_BUG_ON(!card))  		return -ENXIO; -	list_for_each_entry(dev, &card->devices, list) { -		if (snd_device_disconnect(card, dev->device_data) < 0) +	list_for_each_entry_reverse(dev, &card->devices, list) { +		if (__snd_device_disconnect(dev) < 0)  			err = -ENXIO;  	}  	return err; @@ -222,24 +213,12 @@ int snd_device_disconnect_all(struct snd_card *card)   * release all the devices on the card.   * called from init.c   */ -int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) +void snd_device_free_all(struct snd_card *card)  { -	struct snd_device *dev; -	int err; -	unsigned int range_low, range_high, type; +	struct snd_device *dev, *next;  	if (snd_BUG_ON(!card)) -		return -ENXIO; -	range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE; -	range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; -      __again: -	list_for_each_entry(dev, &card->devices, list) { -		type = (__force unsigned int)dev->type; -		if (type >= range_low && type <= range_high) { -			if ((err = snd_device_free(card, dev->device_data)) < 0) -				return err; -			goto __again; -		} -	} -	return 0; +		return; +	list_for_each_entry_safe_reverse(dev, next, &card->devices, list) +		__snd_device_free(dev);  }  | 
