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