linux/sound/core/device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Device management routines
   4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   5 */
   6
   7#include <linux/slab.h>
   8#include <linux/time.h>
   9#include <linux/export.h>
  10#include <linux/errno.h>
  11#include <sound/core.h>
  12
  13/**
  14 * snd_device_new - create an ALSA device component
  15 * @card: the card instance
  16 * @type: the device type, SNDRV_DEV_XXX
  17 * @device_data: the data pointer of this device
  18 * @ops: the operator table
  19 *
  20 * Creates a new device component for the given data pointer.
  21 * The device will be assigned to the card and managed together
  22 * by the card.
  23 *
  24 * The data pointer plays a role as the identifier, too, so the
  25 * pointer address must be unique and unchanged.
  26 *
  27 * Return: Zero if successful, or a negative error code on failure.
  28 */
  29int snd_device_new(struct snd_card *card, enum snd_device_type type,
  30                   void *device_data, const struct snd_device_ops *ops)
  31{
  32        struct snd_device *dev;
  33        struct list_head *p;
  34
  35        if (snd_BUG_ON(!card || !device_data || !ops))
  36                return -ENXIO;
  37        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  38        if (!dev)
  39                return -ENOMEM;
  40        INIT_LIST_HEAD(&dev->list);
  41        dev->card = card;
  42        dev->type = type;
  43        dev->state = SNDRV_DEV_BUILD;
  44        dev->device_data = device_data;
  45        dev->ops = ops;
  46
  47        /* insert the entry in an incrementally sorted list */
  48        list_for_each_prev(p, &card->devices) {
  49                struct snd_device *pdev = list_entry(p, struct snd_device, list);
  50                if ((unsigned int)pdev->type <= (unsigned int)type)
  51                        break;
  52        }
  53
  54        list_add(&dev->list, p);
  55        return 0;
  56}
  57EXPORT_SYMBOL(snd_device_new);
  58
  59static void __snd_device_disconnect(struct snd_device *dev)
  60{
  61        if (dev->state == SNDRV_DEV_REGISTERED) {
  62                if (dev->ops->dev_disconnect &&
  63                    dev->ops->dev_disconnect(dev))
  64                        dev_err(dev->card->dev, "device disconnect failure\n");
  65                dev->state = SNDRV_DEV_DISCONNECTED;
  66        }
  67}
  68
  69static void __snd_device_free(struct snd_device *dev)
  70{
  71        /* unlink */
  72        list_del(&dev->list);
  73
  74        __snd_device_disconnect(dev);
  75        if (dev->ops->dev_free) {
  76                if (dev->ops->dev_free(dev))
  77                        dev_err(dev->card->dev, "device free failure\n");
  78        }
  79        kfree(dev);
  80}
  81
  82static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
  83{
  84        struct snd_device *dev;
  85
  86        list_for_each_entry(dev, &card->devices, list)
  87                if (dev->device_data == device_data)
  88                        return dev;
  89
  90        return NULL;
  91}
  92
  93/**
  94 * snd_device_disconnect - disconnect the device
  95 * @card: the card instance
  96 * @device_data: the data pointer to disconnect
  97 *
  98 * Turns the device into the disconnection state, invoking
  99 * dev_disconnect callback, if the device was already registered.
 100 *
 101 * Usually called from snd_card_disconnect().
 102 *
 103 * Return: Zero if successful, or a negative error code on failure or if the
 104 * device not found.
 105 */
 106void snd_device_disconnect(struct snd_card *card, void *device_data)
 107{
 108        struct snd_device *dev;
 109
 110        if (snd_BUG_ON(!card || !device_data))
 111                return;
 112        dev = look_for_dev(card, device_data);
 113        if (dev)
 114                __snd_device_disconnect(dev);
 115        else
 116                dev_dbg(card->dev, "device disconnect %p (from %pS), not found\n",
 117                        device_data, __builtin_return_address(0));
 118}
 119EXPORT_SYMBOL_GPL(snd_device_disconnect);
 120
 121/**
 122 * snd_device_free - release the device from the card
 123 * @card: the card instance
 124 * @device_data: the data pointer to release
 125 *
 126 * Removes the device from the list on the card and invokes the
 127 * callbacks, dev_disconnect and dev_free, corresponding to the state.
 128 * Then release the device.
 129 */
 130void snd_device_free(struct snd_card *card, void *device_data)
 131{
 132        struct snd_device *dev;
 133        
 134        if (snd_BUG_ON(!card || !device_data))
 135                return;
 136        dev = look_for_dev(card, device_data);
 137        if (dev)
 138                __snd_device_free(dev);
 139        else
 140                dev_dbg(card->dev, "device free %p (from %pS), not found\n",
 141                        device_data, __builtin_return_address(0));
 142}
 143EXPORT_SYMBOL(snd_device_free);
 144
 145static int __snd_device_register(struct snd_device *dev)
 146{
 147        if (dev->state == SNDRV_DEV_BUILD) {
 148                if (dev->ops->dev_register) {
 149                        int err = dev->ops->dev_register(dev);
 150                        if (err < 0)
 151                                return err;
 152                }
 153                dev->state = SNDRV_DEV_REGISTERED;
 154        }
 155        return 0;
 156}
 157
 158/**
 159 * snd_device_register - register the device
 160 * @card: the card instance
 161 * @device_data: the data pointer to register
 162 *
 163 * Registers the device which was already created via
 164 * snd_device_new().  Usually this is called from snd_card_register(),
 165 * but it can be called later if any new devices are created after
 166 * invocation of snd_card_register().
 167 *
 168 * Return: Zero if successful, or a negative error code on failure or if the
 169 * device not found.
 170 */
 171int snd_device_register(struct snd_card *card, void *device_data)
 172{
 173        struct snd_device *dev;
 174
 175        if (snd_BUG_ON(!card || !device_data))
 176                return -ENXIO;
 177        dev = look_for_dev(card, device_data);
 178        if (dev)
 179                return __snd_device_register(dev);
 180        snd_BUG();
 181        return -ENXIO;
 182}
 183EXPORT_SYMBOL(snd_device_register);
 184
 185/*
 186 * register all the devices on the card.
 187 * called from init.c
 188 */
 189int snd_device_register_all(struct snd_card *card)
 190{
 191        struct snd_device *dev;
 192        int err;
 193        
 194        if (snd_BUG_ON(!card))
 195                return -ENXIO;
 196        list_for_each_entry(dev, &card->devices, list) {
 197                err = __snd_device_register(dev);
 198                if (err < 0)
 199                        return err;
 200        }
 201        return 0;
 202}
 203
 204/*
 205 * disconnect all the devices on the card.
 206 * called from init.c
 207 */
 208void snd_device_disconnect_all(struct snd_card *card)
 209{
 210        struct snd_device *dev;
 211
 212        if (snd_BUG_ON(!card))
 213                return;
 214        list_for_each_entry_reverse(dev, &card->devices, list)
 215                __snd_device_disconnect(dev);
 216}
 217
 218/*
 219 * release all the devices on the card.
 220 * called from init.c
 221 */
 222void snd_device_free_all(struct snd_card *card)
 223{
 224        struct snd_device *dev, *next;
 225
 226        if (snd_BUG_ON(!card))
 227                return;
 228        list_for_each_entry_safe_reverse(dev, next, &card->devices, list) {
 229                /* exception: free ctl and lowlevel stuff later */
 230                if (dev->type == SNDRV_DEV_CONTROL ||
 231                    dev->type == SNDRV_DEV_LOWLEVEL)
 232                        continue;
 233                __snd_device_free(dev);
 234        }
 235
 236        /* free all */
 237        list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
 238                __snd_device_free(dev);
 239}
 240
 241/**
 242 * snd_device_get_state - Get the current state of the given device
 243 * @card: the card instance
 244 * @device_data: the data pointer to release
 245 *
 246 * Returns the current state of the given device object.  For the valid
 247 * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or
 248 * @SNDRV_DEV_DISCONNECTED is returned.
 249 * Or for a non-existing device, -1 is returned as an error.
 250 */
 251int snd_device_get_state(struct snd_card *card, void *device_data)
 252{
 253        struct snd_device *dev;
 254
 255        dev = look_for_dev(card, device_data);
 256        if (dev)
 257                return dev->state;
 258        return -1;
 259}
 260EXPORT_SYMBOL_GPL(snd_device_get_state);
 261