1 /* 2 * Device management routines 3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <sound/driver.h> 23 #include <linux/slab.h> 24 #include <linux/time.h> 25 #include <linux/errno.h> 26 #include <sound/core.h> 27 28 /** 29 * snd_device_new - create an ALSA device component 30 * @card: the card instance 31 * @type: the device type, SNDRV_DEV_XXX 32 * @device_data: the data pointer of this device 33 * @ops: the operator table 34 * 35 * Creates a new device component for the given data pointer. 36 * The device will be assigned to the card and managed together 37 * by the card. 38 * 39 * The data pointer plays a role as the identifier, too, so the 40 * pointer address must be unique and unchanged. 41 * 42 * Returns zero if successful, or a negative error code on failure. 43 */ 44 int snd_device_new(struct snd_card *card, snd_device_type_t type, 45 void *device_data, struct snd_device_ops *ops) 46 { 47 struct snd_device *dev; 48 49 snd_assert(card != NULL, return -ENXIO); 50 snd_assert(device_data != NULL, return -ENXIO); 51 snd_assert(ops != NULL, return -ENXIO); 52 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 53 if (dev == NULL) { 54 snd_printk(KERN_ERR "Cannot allocate device\n"); 55 return -ENOMEM; 56 } 57 dev->card = card; 58 dev->type = type; 59 dev->state = SNDRV_DEV_BUILD; 60 dev->device_data = device_data; 61 dev->ops = ops; 62 list_add(&dev->list, &card->devices); /* add to the head of list */ 63 return 0; 64 } 65 66 EXPORT_SYMBOL(snd_device_new); 67 68 /** 69 * snd_device_free - release the device from the card 70 * @card: the card instance 71 * @device_data: the data pointer to release 72 * 73 * Removes the device from the list on the card and invokes the 74 * callbacks, dev_disconnect and dev_free, corresponding to the state. 75 * Then release the device. 76 * 77 * Returns zero if successful, or a negative error code on failure or if the 78 * device not found. 79 */ 80 int snd_device_free(struct snd_card *card, void *device_data) 81 { 82 struct list_head *list; 83 struct snd_device *dev; 84 85 snd_assert(card != NULL, return -ENXIO); 86 snd_assert(device_data != NULL, return -ENXIO); 87 list_for_each(list, &card->devices) { 88 dev = snd_device(list); 89 if (dev->device_data != device_data) 90 continue; 91 /* unlink */ 92 list_del(&dev->list); 93 if (dev->state == SNDRV_DEV_REGISTERED && 94 dev->ops->dev_disconnect) 95 if (dev->ops->dev_disconnect(dev)) 96 snd_printk(KERN_ERR 97 "device disconnect failure\n"); 98 if (dev->ops->dev_free) { 99 if (dev->ops->dev_free(dev)) 100 snd_printk(KERN_ERR "device free failure\n"); 101 } 102 kfree(dev); 103 return 0; 104 } 105 snd_printd("device free %p (from %p), not found\n", device_data, 106 __builtin_return_address(0)); 107 return -ENXIO; 108 } 109 110 EXPORT_SYMBOL(snd_device_free); 111 112 /** 113 * snd_device_disconnect - disconnect the device 114 * @card: the card instance 115 * @device_data: the data pointer to disconnect 116 * 117 * Turns the device into the disconnection state, invoking 118 * dev_disconnect callback, if the device was already registered. 119 * 120 * Usually called from snd_card_disconnect(). 121 * 122 * Returns zero if successful, or a negative error code on failure or if the 123 * device not found. 124 */ 125 int snd_device_disconnect(struct snd_card *card, void *device_data) 126 { 127 struct list_head *list; 128 struct snd_device *dev; 129 130 snd_assert(card != NULL, return -ENXIO); 131 snd_assert(device_data != NULL, return -ENXIO); 132 list_for_each(list, &card->devices) { 133 dev = snd_device(list); 134 if (dev->device_data != device_data) 135 continue; 136 if (dev->state == SNDRV_DEV_REGISTERED && 137 dev->ops->dev_disconnect) { 138 if (dev->ops->dev_disconnect(dev)) 139 snd_printk(KERN_ERR "device disconnect failure\n"); 140 dev->state = SNDRV_DEV_DISCONNECTED; 141 } 142 return 0; 143 } 144 snd_printd("device disconnect %p (from %p), not found\n", device_data, 145 __builtin_return_address(0)); 146 return -ENXIO; 147 } 148 149 /** 150 * snd_device_register - register the device 151 * @card: the card instance 152 * @device_data: the data pointer to register 153 * 154 * Registers the device which was already created via 155 * snd_device_new(). Usually this is called from snd_card_register(), 156 * but it can be called later if any new devices are created after 157 * invocation of snd_card_register(). 158 * 159 * Returns zero if successful, or a negative error code on failure or if the 160 * device not found. 161 */ 162 int snd_device_register(struct snd_card *card, void *device_data) 163 { 164 struct list_head *list; 165 struct snd_device *dev; 166 int err; 167 168 snd_assert(card != NULL, return -ENXIO); 169 snd_assert(device_data != NULL, return -ENXIO); 170 list_for_each(list, &card->devices) { 171 dev = snd_device(list); 172 if (dev->device_data != device_data) 173 continue; 174 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { 175 if ((err = dev->ops->dev_register(dev)) < 0) 176 return err; 177 dev->state = SNDRV_DEV_REGISTERED; 178 return 0; 179 } 180 snd_printd("snd_device_register busy\n"); 181 return -EBUSY; 182 } 183 snd_BUG(); 184 return -ENXIO; 185 } 186 187 EXPORT_SYMBOL(snd_device_register); 188 189 /* 190 * register all the devices on the card. 191 * called from init.c 192 */ 193 int snd_device_register_all(struct snd_card *card) 194 { 195 struct list_head *list; 196 struct snd_device *dev; 197 int err; 198 199 snd_assert(card != NULL, return -ENXIO); 200 list_for_each(list, &card->devices) { 201 dev = snd_device(list); 202 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { 203 if ((err = dev->ops->dev_register(dev)) < 0) 204 return err; 205 dev->state = SNDRV_DEV_REGISTERED; 206 } 207 } 208 return 0; 209 } 210 211 /* 212 * disconnect all the devices on the card. 213 * called from init.c 214 */ 215 int snd_device_disconnect_all(struct snd_card *card) 216 { 217 struct snd_device *dev; 218 struct list_head *list; 219 int err = 0; 220 221 snd_assert(card != NULL, return -ENXIO); 222 list_for_each(list, &card->devices) { 223 dev = snd_device(list); 224 if (snd_device_disconnect(card, dev->device_data) < 0) 225 err = -ENXIO; 226 } 227 return err; 228 } 229 230 /* 231 * release all the devices on the card. 232 * called from init.c 233 */ 234 int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) 235 { 236 struct snd_device *dev; 237 struct list_head *list; 238 int err; 239 unsigned int range_low, range_high; 240 241 snd_assert(card != NULL, return -ENXIO); 242 range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; 243 range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; 244 __again: 245 list_for_each(list, &card->devices) { 246 dev = snd_device(list); 247 if (dev->type >= range_low && dev->type <= range_high) { 248 if ((err = snd_device_free(card, dev->device_data)) < 0) 249 return err; 250 goto __again; 251 } 252 } 253 return 0; 254 } 255