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