Hi,
the recent Linux systems use the auto-probing at boot via udev, and this often screws up the order of device loading, which results in the inconsistent device appearance. A typical case is that you have a PCI onboard and a USB audio device. Sometimes the USB appears as the first device while sometimes (most times) PCI appears as the first.
So far, for fixing this order, we use index module option. That is, add the following to module config:
options snd-onboard index=0 options snd-usb-audio index=1
But this scheme has a problem. It doesn't specify the order of other possible devices. For example, what if I plug a PCMCIA sound card and reboot? Since no index option is given for that, PCMCIA device may be loaded at any unused slot. If it's loaded before other devices, it goes to slot 0. Now, the onboard driver is loaded, and found that the statically assigned slot 0 is already occupied. Ouch, the driver fails and the device gets unusable.
So, obviously, the problem of index option is that it's specific to the driver, and it doesn't give the whole system-wide setting. For overcoming this, I'd like to propose the following new option to snd module. The "slots" option is used to pass the static assignment of known drivers. For example, in the case above, it'd be like the following:
options snd slots=snd-onboard,snd-usb-audio
And you can omit all index options if you want. When a new device is loaded, then the first two slots are avoided, and it's loaded to the third slot in the end.
The experimental patch is below. As you see, the necessary change is minimum, and it doesn't even conflict with the existing index option, too.
Any comments? The module name "slots" is OK?
BTW, one missing feature is the support for built-in drivers. But I don't think it's needed because the built-in drivers are always loaded in prior to others, and thus you can give simply index options for each.
thanks,
Takashi
diff -r 5debd8716290 core/init.c --- a/core/init.c Wed Sep 05 15:08:23 2007 +0200 +++ b/core/init.c Wed Sep 05 19:00:08 2007 +0200 @@ -42,6 +42,40 @@ EXPORT_SYMBOL(snd_cards); EXPORT_SYMBOL(snd_cards);
static DEFINE_MUTEX(snd_card_mutex); + +static char *slots[SNDRV_CARDS]; +module_param_array(slots, charp, NULL, 0444); +MODULE_PARM_DESC(slots, "Module names assigned to the slots."); + +/* return non-zero if the given index is already reserved for another + * module via slots option + */ +static int module_slot_mismatch(struct module *module, int idx) +{ +#ifdef MODULE + char *s1, *s2; + if (!module || !module->name || !slots[idx]) + return 0; + s1 = slots[idx]; + s2 = module->name; + /* compare module name strings + * hyphens are handled as equivalent with underscore + */ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (c1 == '-') + c1 = '_'; + if (c2 == '-') + c2 = '_'; + if (c1 != c2) + return 1; + if (!c1) + break; + } +#endif + return 0; +}
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); @@ -115,6 +149,8 @@ struct snd_card *snd_card_new(int idx, c for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) /* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1<<idx2) { + if (module_slot_mismatch(module, idx2)) + continue; idx = idx2; if (idx >= snd_ecards_limit) snd_ecards_limit = idx + 1;