Branch data Line data Source code
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 : : */ 29 : 3 : int snd_device_new(struct snd_card *card, enum snd_device_type type, 30 : : void *device_data, struct snd_device_ops *ops) 31 : : { 32 : : struct snd_device *dev; 33 : : struct list_head *p; 34 : : 35 : 3 : if (snd_BUG_ON(!card || !device_data || !ops)) 36 : : return -ENXIO; 37 : 3 : dev = kzalloc(sizeof(*dev), GFP_KERNEL); 38 : 3 : if (!dev) 39 : : return -ENOMEM; 40 : 3 : INIT_LIST_HEAD(&dev->list); 41 : 3 : dev->card = card; 42 : 3 : dev->type = type; 43 : 3 : dev->state = SNDRV_DEV_BUILD; 44 : 3 : dev->device_data = device_data; 45 : 3 : dev->ops = ops; 46 : : 47 : : /* insert the entry in an incrementally sorted list */ 48 : 3 : list_for_each_prev(p, &card->devices) { 49 : : struct snd_device *pdev = list_entry(p, struct snd_device, list); 50 : 3 : if ((unsigned int)pdev->type <= (unsigned int)type) 51 : : break; 52 : : } 53 : : 54 : : list_add(&dev->list, p); 55 : 3 : return 0; 56 : : } 57 : : EXPORT_SYMBOL(snd_device_new); 58 : : 59 : 0 : static void __snd_device_disconnect(struct snd_device *dev) 60 : : { 61 : 0 : if (dev->state == SNDRV_DEV_REGISTERED) { 62 : 0 : if (dev->ops->dev_disconnect && 63 : 0 : dev->ops->dev_disconnect(dev)) 64 : 0 : dev_err(dev->card->dev, "device disconnect failure\n"); 65 : 0 : dev->state = SNDRV_DEV_DISCONNECTED; 66 : : } 67 : 0 : } 68 : : 69 : 0 : static void __snd_device_free(struct snd_device *dev) 70 : : { 71 : : /* unlink */ 72 : : list_del(&dev->list); 73 : : 74 : 0 : __snd_device_disconnect(dev); 75 : 0 : if (dev->ops->dev_free) { 76 : 0 : if (dev->ops->dev_free(dev)) 77 : 0 : dev_err(dev->card->dev, "device free failure\n"); 78 : : } 79 : 0 : kfree(dev); 80 : 0 : } 81 : : 82 : : static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) 83 : : { 84 : : struct snd_device *dev; 85 : : 86 : 3 : list_for_each_entry(dev, &card->devices, list) 87 : 3 : if (dev->device_data == device_data) 88 : 3 : 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 : : */ 106 : 0 : void snd_device_disconnect(struct snd_card *card, void *device_data) 107 : : { 108 : : struct snd_device *dev; 109 : : 110 : 0 : if (snd_BUG_ON(!card || !device_data)) 111 : 0 : return; 112 : : dev = look_for_dev(card, device_data); 113 : 0 : if (dev) 114 : 0 : __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 : : } 119 : : EXPORT_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 : : */ 130 : 0 : void snd_device_free(struct snd_card *card, void *device_data) 131 : : { 132 : : struct snd_device *dev; 133 : : 134 : 0 : if (snd_BUG_ON(!card || !device_data)) 135 : 0 : return; 136 : : dev = look_for_dev(card, device_data); 137 : 0 : if (dev) 138 : 0 : __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 : : } 143 : : EXPORT_SYMBOL(snd_device_free); 144 : : 145 : : static int __snd_device_register(struct snd_device *dev) 146 : : { 147 : 3 : if (dev->state == SNDRV_DEV_BUILD) { 148 : 3 : if (dev->ops->dev_register) { 149 : 3 : int err = dev->ops->dev_register(dev); 150 : 3 : if (err < 0) 151 : : return err; 152 : : } 153 : 3 : 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 : : */ 171 : 3 : int snd_device_register(struct snd_card *card, void *device_data) 172 : : { 173 : : struct snd_device *dev; 174 : : 175 : 3 : if (snd_BUG_ON(!card || !device_data)) 176 : : return -ENXIO; 177 : : dev = look_for_dev(card, device_data); 178 : 3 : if (dev) 179 : 3 : return __snd_device_register(dev); 180 : : snd_BUG(); 181 : : return -ENXIO; 182 : : } 183 : : EXPORT_SYMBOL(snd_device_register); 184 : : 185 : : /* 186 : : * register all the devices on the card. 187 : : * called from init.c 188 : : */ 189 : 3 : int snd_device_register_all(struct snd_card *card) 190 : : { 191 : : struct snd_device *dev; 192 : : int err; 193 : : 194 : 3 : if (snd_BUG_ON(!card)) 195 : : return -ENXIO; 196 : 3 : list_for_each_entry(dev, &card->devices, list) { 197 : : err = __snd_device_register(dev); 198 : 3 : if (err < 0) 199 : 0 : return err; 200 : : } 201 : : return 0; 202 : : } 203 : : 204 : : /* 205 : : * disconnect all the devices on the card. 206 : : * called from init.c 207 : : */ 208 : 0 : void snd_device_disconnect_all(struct snd_card *card) 209 : : { 210 : : struct snd_device *dev; 211 : : 212 : 0 : if (snd_BUG_ON(!card)) 213 : 0 : return; 214 : 0 : list_for_each_entry_reverse(dev, &card->devices, list) 215 : 0 : __snd_device_disconnect(dev); 216 : : } 217 : : 218 : : /* 219 : : * release all the devices on the card. 220 : : * called from init.c 221 : : */ 222 : 0 : void snd_device_free_all(struct snd_card *card) 223 : : { 224 : : struct snd_device *dev, *next; 225 : : 226 : 0 : if (snd_BUG_ON(!card)) 227 : 0 : return; 228 : 0 : list_for_each_entry_safe_reverse(dev, next, &card->devices, list) { 229 : : /* exception: free ctl and lowlevel stuff later */ 230 : 0 : if (dev->type == SNDRV_DEV_CONTROL || 231 : : dev->type == SNDRV_DEV_LOWLEVEL) 232 : 0 : continue; 233 : 0 : __snd_device_free(dev); 234 : : } 235 : : 236 : : /* free all */ 237 : 0 : list_for_each_entry_safe_reverse(dev, next, &card->devices, list) 238 : 0 : __snd_device_free(dev); 239 : : }