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 /** 67 * snd_device_free - release the device from the card 68 * @card: the card instance 69 * @device_data: the data pointer to release 70 * 71 * Removes the device from the list on the card and invokes the 72 * callback, dev_unregister or dev_free, corresponding to the state. 73 * Then release the device. 74 * 75 * Returns zero if successful, or a negative error code on failure or if the 76 * device not found. 77 */ 78 int snd_device_free(struct snd_card *card, void *device_data) 79 { 80 struct list_head *list; 81 struct snd_device *dev; 82 83 snd_assert(card != NULL, return -ENXIO); 84 snd_assert(device_data != NULL, return -ENXIO); 85 list_for_each(list, &card->devices) { 86 dev = snd_device(list); 87 if (dev->device_data != device_data) 88 continue; 89 /* unlink */ 90 list_del(&dev->list); 91 if ((dev->state == SNDRV_DEV_REGISTERED || 92 dev->state == SNDRV_DEV_DISCONNECTED) && 93 dev->ops->dev_unregister) { 94 if (dev->ops->dev_unregister(dev)) 95 snd_printk(KERN_ERR "device unregister failure\n"); 96 } else { 97 if (dev->ops->dev_free) { 98 if (dev->ops->dev_free(dev)) 99 snd_printk(KERN_ERR "device free failure\n"); 100 } 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 /** 111 * snd_device_disconnect - disconnect the device 112 * @card: the card instance 113 * @device_data: the data pointer to disconnect 114 * 115 * Turns the device into the disconnection state, invoking 116 * dev_disconnect callback, if the device was already registered. 117 * 118 * Usually called from snd_card_disconnect(). 119 * 120 * Returns zero if successful, or a negative error code on failure or if the 121 * device not found. 122 */ 123 int snd_device_disconnect(struct snd_card *card, void *device_data) 124 { 125 struct list_head *list; 126 struct snd_device *dev; 127 128 snd_assert(card != NULL, return -ENXIO); 129 snd_assert(device_data != NULL, return -ENXIO); 130 list_for_each(list, &card->devices) { 131 dev = snd_device(list); 132 if (dev->device_data != device_data) 133 continue; 134 if (dev->state == SNDRV_DEV_REGISTERED && 135 dev->ops->dev_disconnect) { 136 if (dev->ops->dev_disconnect(dev)) 137 snd_printk(KERN_ERR "device disconnect failure\n"); 138 dev->state = SNDRV_DEV_DISCONNECTED; 139 } 140 return 0; 141 } 142 snd_printd("device disconnect %p (from %p), not found\n", device_data, 143 __builtin_return_address(0)); 144 return -ENXIO; 145 } 146 147 /** 148 * snd_device_register - register the device 149 * @card: the card instance 150 * @device_data: the data pointer to register 151 * 152 * Registers the device which was already created via 153 * snd_device_new(). Usually this is called from snd_card_register(), 154 * but it can be called later if any new devices are created after 155 * invocation of snd_card_register(). 156 * 157 * Returns zero if successful, or a negative error code on failure or if the 158 * device not found. 159 */ 160 int snd_device_register(struct snd_card *card, void *device_data) 161 { 162 struct list_head *list; 163 struct snd_device *dev; 164 int err; 165 166 snd_assert(card != NULL, return -ENXIO); 167 snd_assert(device_data != NULL, return -ENXIO); 168 list_for_each(list, &card->devices) { 169 dev = snd_device(list); 170 if (dev->device_data != device_data) 171 continue; 172 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { 173 if ((err = dev->ops->dev_register(dev)) < 0) 174 return err; 175 dev->state = SNDRV_DEV_REGISTERED; 176 return 0; 177 } 178 snd_printd("snd_device_register busy\n"); 179 return -EBUSY; 180 } 181 snd_BUG(); 182 return -ENXIO; 183 } 184 185 /* 186 * register all the devices on the card. 187 * called from init.c 188 */ 189 int snd_device_register_all(struct snd_card *card) 190 { 191 struct list_head *list; 192 struct snd_device *dev; 193 int err; 194 195 snd_assert(card != NULL, return -ENXIO); 196 list_for_each(list, &card->devices) { 197 dev = snd_device(list); 198 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { 199 if ((err = dev->ops->dev_register(dev)) < 0) 200 return err; 201 dev->state = SNDRV_DEV_REGISTERED; 202 } 203 } 204 return 0; 205 } 206 207 /* 208 * disconnect all the devices on the card. 209 * called from init.c 210 */ 211 int snd_device_disconnect_all(struct snd_card *card) 212 { 213 struct snd_device *dev; 214 struct list_head *list; 215 int err = 0; 216 217 snd_assert(card != NULL, return -ENXIO); 218 list_for_each(list, &card->devices) { 219 dev = snd_device(list); 220 if (snd_device_disconnect(card, dev->device_data) < 0) 221 err = -ENXIO; 222 } 223 return err; 224 } 225 226 /* 227 * release all the devices on the card. 228 * called from init.c 229 */ 230 int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) 231 { 232 struct snd_device *dev; 233 struct list_head *list; 234 int err; 235 unsigned int range_low, range_high; 236 237 snd_assert(card != NULL, return -ENXIO); 238 range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; 239 range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; 240 __again: 241 list_for_each(list, &card->devices) { 242 dev = snd_device(list); 243 if (dev->type >= range_low && dev->type <= range_high) { 244 if ((err = snd_device_free(card, dev->device_data)) < 0) 245 return err; 246 goto __again; 247 } 248 } 249 return 0; 250 } 251