Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: Use priority list for managing device list

Basically, the device type specifies the priority of the device to be
registered / freed, too. However, the priority value isn't well
utilized but only it's checked as a group. This results in
inconsistent register and free order (where each of them should be in
reversed direction).

This patch simplifies the device list management code by simply
inserting a list entry at creation time in an incremental order for
the priority value. Since we can just follow the link for register,
disconnect and free calls, we don't have to specify the group; so the
whole enum definitions are also simplified as well.

The visible change to outside is that the priorities of some object
types are revisited. For example, now the SNDRV_DEV_LOWLEVEL object
is registered before others (control, PCM, etc) and, in return,
released after others. Similarly, SNDRV_DEV_CODEC is in a lower
priority than SNDRV_DEV_BUS for ensuring the dependency.

Also, the unused SNDRV_DEV_TOPLEVEL, SNDRV_DEV_LOWLEVEL_PRE and
SNDRV_DEV_LOWLEVEL_NORMAL are removed as a cleanup.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+50 -58
+10 -18
include/sound/core.h
··· 46 46 47 47 /* device allocation stuff */ 48 48 49 - #define SNDRV_DEV_TYPE_RANGE_SIZE 0x1000 50 - 49 + /* type of the object used in snd_device_*() 50 + * this also defines the calling order 51 + */ 51 52 enum snd_device_type { 52 - SNDRV_DEV_TOPLEVEL = 0, 53 - SNDRV_DEV_CONTROL = 1, 54 - SNDRV_DEV_LOWLEVEL_PRE = 2, 55 - SNDRV_DEV_LOWLEVEL_NORMAL = 0x1000, 53 + SNDRV_DEV_LOWLEVEL, 54 + SNDRV_DEV_CONTROL, 55 + SNDRV_DEV_INFO, 56 + SNDRV_DEV_BUS, 57 + SNDRV_DEV_CODEC, 56 58 SNDRV_DEV_PCM, 59 + SNDRV_DEV_COMPRESS, 57 60 SNDRV_DEV_RAWMIDI, 58 61 SNDRV_DEV_TIMER, 59 62 SNDRV_DEV_SEQUENCER, 60 63 SNDRV_DEV_HWDEP, 61 - SNDRV_DEV_INFO, 62 - SNDRV_DEV_BUS, 63 - SNDRV_DEV_CODEC, 64 64 SNDRV_DEV_JACK, 65 - SNDRV_DEV_COMPRESS, 66 - SNDRV_DEV_LOWLEVEL = 0x2000, 67 65 }; 68 66 69 67 enum snd_device_state { 70 68 SNDRV_DEV_BUILD, 71 69 SNDRV_DEV_REGISTERED, 72 70 SNDRV_DEV_DISCONNECTED, 73 - }; 74 - 75 - enum snd_device_cmd { 76 - SNDRV_DEV_CMD_PRE, 77 - SNDRV_DEV_CMD_NORMAL, 78 - SNDRV_DEV_CMD_POST, 79 71 }; 80 72 81 73 struct snd_device; ··· 312 320 int snd_device_disconnect(struct snd_card *card, void *device_data); 313 321 int snd_device_disconnect_all(struct snd_card *card); 314 322 int snd_device_free(struct snd_card *card, void *device_data); 315 - int snd_device_free_all(struct snd_card *card, enum snd_device_cmd cmd); 323 + int snd_device_free_all(struct snd_card *card); 316 324 317 325 /* isadma.c */ 318 326
+37 -29
sound/core/device.c
··· 45 45 void *device_data, struct snd_device_ops *ops) 46 46 { 47 47 struct snd_device *dev; 48 + struct list_head *p; 48 49 49 50 if (snd_BUG_ON(!card || !device_data || !ops)) 50 51 return -ENXIO; ··· 54 53 dev_err(card->dev, "Cannot allocate device, type=%d\n", type); 55 54 return -ENOMEM; 56 55 } 56 + INIT_LIST_HEAD(&dev->list); 57 57 dev->card = card; 58 58 dev->type = type; 59 59 dev->state = SNDRV_DEV_BUILD; 60 60 dev->device_data = device_data; 61 61 dev->ops = ops; 62 - list_add(&dev->list, &card->devices); /* add to the head of list */ 62 + 63 + /* insert the entry in an incrementally sorted list */ 64 + list_for_each_prev(p, &card->devices) { 65 + struct snd_device *pdev = list_entry(p, struct snd_device, list); 66 + if ((unsigned int)pdev->type <= (unsigned int)type) 67 + break; 68 + } 69 + 70 + list_add(&dev->list, p); 63 71 return 0; 64 72 } 65 - 66 73 EXPORT_SYMBOL(snd_device_new); 74 + 75 + static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) 76 + { 77 + struct snd_device *dev; 78 + 79 + list_for_each_entry(dev, &card->devices, list) 80 + if (dev->device_data == device_data) 81 + return dev; 82 + 83 + return NULL; 84 + } 67 85 68 86 /** 69 87 * snd_device_free - release the device from the card ··· 102 82 103 83 if (snd_BUG_ON(!card || !device_data)) 104 84 return -ENXIO; 105 - list_for_each_entry(dev, &card->devices, list) { 106 - if (dev->device_data != device_data) 107 - continue; 85 + dev = look_for_dev(card, device_data); 86 + if (dev) { 108 87 /* unlink */ 109 88 list_del(&dev->list); 110 89 if (dev->state == SNDRV_DEV_REGISTERED && ··· 122 103 device_data, __builtin_return_address(0)); 123 104 return -ENXIO; 124 105 } 125 - 126 106 EXPORT_SYMBOL(snd_device_free); 127 107 128 108 /** ··· 143 125 144 126 if (snd_BUG_ON(!card || !device_data)) 145 127 return -ENXIO; 146 - list_for_each_entry(dev, &card->devices, list) { 147 - if (dev->device_data != device_data) 148 - continue; 128 + dev = look_for_dev(card, device_data); 129 + if (dev) { 149 130 if (dev->state == SNDRV_DEV_REGISTERED && 150 131 dev->ops->dev_disconnect) { 151 132 if (dev->ops->dev_disconnect(dev)) ··· 179 162 180 163 if (snd_BUG_ON(!card || !device_data)) 181 164 return -ENXIO; 182 - list_for_each_entry(dev, &card->devices, list) { 183 - if (dev->device_data != device_data) 184 - continue; 165 + dev = look_for_dev(card, device_data); 166 + if (dev) { 185 167 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { 186 168 if ((err = dev->ops->dev_register(dev)) < 0) 187 169 return err; ··· 193 177 snd_BUG(); 194 178 return -ENXIO; 195 179 } 196 - 197 180 EXPORT_SYMBOL(snd_device_register); 198 181 199 182 /* ··· 227 212 228 213 if (snd_BUG_ON(!card)) 229 214 return -ENXIO; 230 - list_for_each_entry(dev, &card->devices, list) { 215 + list_for_each_entry_reverse(dev, &card->devices, list) { 231 216 if (snd_device_disconnect(card, dev->device_data) < 0) 232 217 err = -ENXIO; 233 218 } ··· 238 223 * release all the devices on the card. 239 224 * called from init.c 240 225 */ 241 - int snd_device_free_all(struct snd_card *card, enum snd_device_cmd cmd) 226 + int snd_device_free_all(struct snd_card *card) 242 227 { 243 - struct snd_device *dev; 244 - int err; 245 - unsigned int range_low, range_high, type; 228 + struct snd_device *dev, *next; 229 + int ret = 0; 246 230 247 231 if (snd_BUG_ON(!card)) 248 232 return -ENXIO; 249 - range_low = (unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE; 250 - range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; 251 - __again: 252 - list_for_each_entry(dev, &card->devices, list) { 253 - type = (unsigned int)dev->type; 254 - if (type >= range_low && type <= range_high) { 255 - if ((err = snd_device_free(card, dev->device_data)) < 0) 256 - return err; 257 - goto __again; 258 - } 233 + list_for_each_entry_safe_reverse(dev, next, &card->devices, list) { 234 + int err = snd_device_free(card, dev->device_data); 235 + if (err < 0) 236 + ret = err; 259 237 } 260 - return 0; 238 + return ret; 261 239 }
+3 -11
sound/core/init.c
··· 266 266 return 0; 267 267 268 268 __error_ctl: 269 - snd_device_free_all(card, SNDRV_DEV_CMD_PRE); 269 + snd_device_free_all(card); 270 270 __error: 271 271 put_device(&card->card_dev); 272 272 return err; ··· 454 454 if (snd_mixer_oss_notify_callback) 455 455 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); 456 456 #endif 457 - if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) { 458 - dev_err(card->dev, "unable to free all devices (pre)\n"); 459 - /* Fatal, but this situation should never occur */ 460 - } 461 - if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) { 462 - dev_err(card->dev, "unable to free all devices (normal)\n"); 463 - /* Fatal, but this situation should never occur */ 464 - } 465 - if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) { 466 - dev_err(card->dev, "unable to free all devices (post)\n"); 457 + if (snd_device_free_all(card) < 0) { 458 + dev_err(card->dev, "unable to free all devices\n"); 467 459 /* Fatal, but this situation should never occur */ 468 460 } 469 461 if (card->private_free)