Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Device management routines
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/slab.h>
0008 #include <linux/time.h>
0009 #include <linux/export.h>
0010 #include <linux/errno.h>
0011 #include <sound/core.h>
0012 
0013 /**
0014  * snd_device_new - create an ALSA device component
0015  * @card: the card instance
0016  * @type: the device type, SNDRV_DEV_XXX
0017  * @device_data: the data pointer of this device
0018  * @ops: the operator table
0019  *
0020  * Creates a new device component for the given data pointer.
0021  * The device will be assigned to the card and managed together
0022  * by the card.
0023  *
0024  * The data pointer plays a role as the identifier, too, so the
0025  * pointer address must be unique and unchanged.
0026  *
0027  * Return: Zero if successful, or a negative error code on failure.
0028  */
0029 int snd_device_new(struct snd_card *card, enum snd_device_type type,
0030            void *device_data, const struct snd_device_ops *ops)
0031 {
0032     struct snd_device *dev;
0033     struct list_head *p;
0034 
0035     if (snd_BUG_ON(!card || !device_data || !ops))
0036         return -ENXIO;
0037     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0038     if (!dev)
0039         return -ENOMEM;
0040     INIT_LIST_HEAD(&dev->list);
0041     dev->card = card;
0042     dev->type = type;
0043     dev->state = SNDRV_DEV_BUILD;
0044     dev->device_data = device_data;
0045     dev->ops = ops;
0046 
0047     /* insert the entry in an incrementally sorted list */
0048     list_for_each_prev(p, &card->devices) {
0049         struct snd_device *pdev = list_entry(p, struct snd_device, list);
0050         if ((unsigned int)pdev->type <= (unsigned int)type)
0051             break;
0052     }
0053 
0054     list_add(&dev->list, p);
0055     return 0;
0056 }
0057 EXPORT_SYMBOL(snd_device_new);
0058 
0059 static void __snd_device_disconnect(struct snd_device *dev)
0060 {
0061     if (dev->state == SNDRV_DEV_REGISTERED) {
0062         if (dev->ops->dev_disconnect &&
0063             dev->ops->dev_disconnect(dev))
0064             dev_err(dev->card->dev, "device disconnect failure\n");
0065         dev->state = SNDRV_DEV_DISCONNECTED;
0066     }
0067 }
0068 
0069 static void __snd_device_free(struct snd_device *dev)
0070 {
0071     /* unlink */
0072     list_del(&dev->list);
0073 
0074     __snd_device_disconnect(dev);
0075     if (dev->ops->dev_free) {
0076         if (dev->ops->dev_free(dev))
0077             dev_err(dev->card->dev, "device free failure\n");
0078     }
0079     kfree(dev);
0080 }
0081 
0082 static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
0083 {
0084     struct snd_device *dev;
0085 
0086     list_for_each_entry(dev, &card->devices, list)
0087         if (dev->device_data == device_data)
0088             return dev;
0089 
0090     return NULL;
0091 }
0092 
0093 /**
0094  * snd_device_disconnect - disconnect the device
0095  * @card: the card instance
0096  * @device_data: the data pointer to disconnect
0097  *
0098  * Turns the device into the disconnection state, invoking
0099  * dev_disconnect callback, if the device was already registered.
0100  *
0101  * Usually called from snd_card_disconnect().
0102  *
0103  * Return: Zero if successful, or a negative error code on failure or if the
0104  * device not found.
0105  */
0106 void snd_device_disconnect(struct snd_card *card, void *device_data)
0107 {
0108     struct snd_device *dev;
0109 
0110     if (snd_BUG_ON(!card || !device_data))
0111         return;
0112     dev = look_for_dev(card, device_data);
0113     if (dev)
0114         __snd_device_disconnect(dev);
0115     else
0116         dev_dbg(card->dev, "device disconnect %p (from %pS), not found\n",
0117             device_data, __builtin_return_address(0));
0118 }
0119 EXPORT_SYMBOL_GPL(snd_device_disconnect);
0120 
0121 /**
0122  * snd_device_free - release the device from the card
0123  * @card: the card instance
0124  * @device_data: the data pointer to release
0125  *
0126  * Removes the device from the list on the card and invokes the
0127  * callbacks, dev_disconnect and dev_free, corresponding to the state.
0128  * Then release the device.
0129  */
0130 void snd_device_free(struct snd_card *card, void *device_data)
0131 {
0132     struct snd_device *dev;
0133     
0134     if (snd_BUG_ON(!card || !device_data))
0135         return;
0136     dev = look_for_dev(card, device_data);
0137     if (dev)
0138         __snd_device_free(dev);
0139     else
0140         dev_dbg(card->dev, "device free %p (from %pS), not found\n",
0141             device_data, __builtin_return_address(0));
0142 }
0143 EXPORT_SYMBOL(snd_device_free);
0144 
0145 static int __snd_device_register(struct snd_device *dev)
0146 {
0147     if (dev->state == SNDRV_DEV_BUILD) {
0148         if (dev->ops->dev_register) {
0149             int err = dev->ops->dev_register(dev);
0150             if (err < 0)
0151                 return err;
0152         }
0153         dev->state = SNDRV_DEV_REGISTERED;
0154     }
0155     return 0;
0156 }
0157 
0158 /**
0159  * snd_device_register - register the device
0160  * @card: the card instance
0161  * @device_data: the data pointer to register
0162  *
0163  * Registers the device which was already created via
0164  * snd_device_new().  Usually this is called from snd_card_register(),
0165  * but it can be called later if any new devices are created after
0166  * invocation of snd_card_register().
0167  *
0168  * Return: Zero if successful, or a negative error code on failure or if the
0169  * device not found.
0170  */
0171 int snd_device_register(struct snd_card *card, void *device_data)
0172 {
0173     struct snd_device *dev;
0174 
0175     if (snd_BUG_ON(!card || !device_data))
0176         return -ENXIO;
0177     dev = look_for_dev(card, device_data);
0178     if (dev)
0179         return __snd_device_register(dev);
0180     snd_BUG();
0181     return -ENXIO;
0182 }
0183 EXPORT_SYMBOL(snd_device_register);
0184 
0185 /*
0186  * register all the devices on the card.
0187  * called from init.c
0188  */
0189 int snd_device_register_all(struct snd_card *card)
0190 {
0191     struct snd_device *dev;
0192     int err;
0193     
0194     if (snd_BUG_ON(!card))
0195         return -ENXIO;
0196     list_for_each_entry(dev, &card->devices, list) {
0197         err = __snd_device_register(dev);
0198         if (err < 0)
0199             return err;
0200     }
0201     return 0;
0202 }
0203 
0204 /*
0205  * disconnect all the devices on the card.
0206  * called from init.c
0207  */
0208 void snd_device_disconnect_all(struct snd_card *card)
0209 {
0210     struct snd_device *dev;
0211 
0212     if (snd_BUG_ON(!card))
0213         return;
0214     list_for_each_entry_reverse(dev, &card->devices, list)
0215         __snd_device_disconnect(dev);
0216 }
0217 
0218 /*
0219  * release all the devices on the card.
0220  * called from init.c
0221  */
0222 void snd_device_free_all(struct snd_card *card)
0223 {
0224     struct snd_device *dev, *next;
0225 
0226     if (snd_BUG_ON(!card))
0227         return;
0228     list_for_each_entry_safe_reverse(dev, next, &card->devices, list) {
0229         /* exception: free ctl and lowlevel stuff later */
0230         if (dev->type == SNDRV_DEV_CONTROL ||
0231             dev->type == SNDRV_DEV_LOWLEVEL)
0232             continue;
0233         __snd_device_free(dev);
0234     }
0235 
0236     /* free all */
0237     list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
0238         __snd_device_free(dev);
0239 }
0240 
0241 /**
0242  * snd_device_get_state - Get the current state of the given device
0243  * @card: the card instance
0244  * @device_data: the data pointer to release
0245  *
0246  * Returns the current state of the given device object.  For the valid
0247  * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or
0248  * @SNDRV_DEV_DISCONNECTED is returned.
0249  * Or for a non-existing device, -1 is returned as an error.
0250  *
0251  * Return: the current state, or -1 if not found
0252  */
0253 int snd_device_get_state(struct snd_card *card, void *device_data)
0254 {
0255     struct snd_device *dev;
0256 
0257     dev = look_for_dev(card, device_data);
0258     if (dev)
0259         return dev->state;
0260     return -1;
0261 }
0262 EXPORT_SYMBOL_GPL(snd_device_get_state);