[ALSA] dynamic minors (4/6): dynamic minor number allocation
Clemens Ladisch [Sun, 20 Nov 2005 13:07:47 +0000 (14:07 +0100)]
Modules: ALSA Core,ALSA Minor Numbers

Add an option to allocate device file minor numbers dynamically.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>

include/sound/minors.h
sound/core/Kconfig
sound/core/sound.c

index a17b5c9..46bcd20 100644 (file)
 #define SNDRV_MINOR_DEVICE(minor)      ((minor) & 0x001f)
 #define SNDRV_MINOR(card, dev)         (((card) << 5) | (dev))
 
-#define SNDRV_MINOR_CONTROL            0       /* 0 - 0 */
+/* these minors can still be used for autoloading devices (/dev/aload*) */
+#define SNDRV_MINOR_CONTROL            0       /* 0 */
 #define SNDRV_MINOR_GLOBAL             1       /* 1 */
 #define SNDRV_MINOR_SEQUENCER          (SNDRV_MINOR_GLOBAL + 0 * 32)
 #define SNDRV_MINOR_TIMER              (SNDRV_MINOR_GLOBAL + 1 * 32)
+
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+                                               /* 2 - 3 (reserved) */
 #define SNDRV_MINOR_HWDEP              4       /* 4 - 7 */
-#define SNDRV_MINOR_HWDEPS             4
 #define SNDRV_MINOR_RAWMIDI            8       /* 8 - 15 */
-#define SNDRV_MINOR_RAWMIDIS           8
 #define SNDRV_MINOR_PCM_PLAYBACK       16      /* 16 - 23 */
 #define SNDRV_MINOR_PCM_CAPTURE                24      /* 24 - 31 */
-#define SNDRV_MINOR_PCMS               8
 
+/* same as first respective minor number to make minor allocation easier */
 #define SNDRV_DEVICE_TYPE_CONTROL      SNDRV_MINOR_CONTROL
 #define SNDRV_DEVICE_TYPE_HWDEP                SNDRV_MINOR_HWDEP
 #define SNDRV_DEVICE_TYPE_RAWMIDI      SNDRV_MINOR_RAWMIDI
 #define SNDRV_DEVICE_TYPE_SEQUENCER    SNDRV_MINOR_SEQUENCER
 #define SNDRV_DEVICE_TYPE_TIMER                SNDRV_MINOR_TIMER
 
+#else /* CONFIG_SND_DYNAMIC_MINORS */
+
+enum {
+       SNDRV_DEVICE_TYPE_CONTROL,
+       SNDRV_DEVICE_TYPE_SEQUENCER,
+       SNDRV_DEVICE_TYPE_TIMER,
+       SNDRV_DEVICE_TYPE_HWDEP,
+       SNDRV_DEVICE_TYPE_RAWMIDI,
+       SNDRV_DEVICE_TYPE_PCM_PLAYBACK,
+       SNDRV_DEVICE_TYPE_PCM_CAPTURE,
+};
+
+#endif /* CONFIG_SND_DYNAMIC_MINORS */
+
+#define SNDRV_MINOR_HWDEPS             4
+#define SNDRV_MINOR_RAWMIDIS           8
+#define SNDRV_MINOR_PCMS               8
+
+
 #ifdef CONFIG_SND_OSSEMUL
 
 #define SNDRV_MINOR_OSS_DEVICES                16
index b46efff..83cbe20 100644 (file)
@@ -111,6 +111,17 @@ config SND_SEQ_RTCTIMER_DEFAULT
 
          If in doubt, say Y.
 
+config SND_DYNAMIC_MINORS
+       bool "Dynamic device file minor numbers (EXPERIMENTAL)"
+       depends on SND && EXPERIMENTAL
+       help
+         If you say Y here, the minor numbers of ALSA device files in
+         /dev/snd/ are allocated dynamically.  This allows you to have
+         more than 8 sound cards, but requires a dynamic device file
+         system like udev.
+
+         If you are unsure about this, say N here.
+
 config SND_VERBOSE_PRINTK
        bool "Verbose printk"
        depends on SND
index 1e5eca5..5e22283 100644 (file)
@@ -133,29 +133,34 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
 
 static int snd_open(struct inode *inode, struct file *file)
 {
-       int minor = iminor(inode);
-       int card = SNDRV_MINOR_CARD(minor);
-       int dev = SNDRV_MINOR_DEVICE(minor);
+       unsigned int minor = iminor(inode);
        struct snd_minor *mptr = NULL;
        struct file_operations *old_fops;
        int err = 0;
 
-       if (dev != SNDRV_MINOR_GLOBAL) {
-               if (snd_cards[card] == NULL) {
+       if (minor > ARRAY_SIZE(snd_minors))
+               return -ENODEV;
+       mptr = snd_minors[minor];
+       if (mptr == NULL) {
 #ifdef CONFIG_KMOD
-                       snd_request_card(card);
+               int dev = SNDRV_MINOR_DEVICE(minor);
+               if (dev == SNDRV_MINOR_CONTROL) {
+                       /* /dev/aloadC? */
+                       int card = SNDRV_MINOR_CARD(minor);
                        if (snd_cards[card] == NULL)
-#endif
-                               return -ENODEV;
-               }
-       } else {
-#ifdef CONFIG_KMOD
-               if ((mptr = snd_minors[minor]) == NULL)
+                               snd_request_card(card);
+               } else if (dev == SNDRV_MINOR_GLOBAL) {
+                       /* /dev/aloadSEQ */
                        snd_request_other(minor);
+               }
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+               /* /dev/snd/{controlC?,seq} */
+               mptr = snd_minors[minor];
+               if (mptr == NULL)
+#endif
 #endif
+                       return -ENODEV;
        }
-       if (mptr == NULL && (mptr = snd_minors[minor]) == NULL)
-               return -ENODEV;
        old_fops = file->f_op;
        file->f_op = fops_get(mptr->f_ops);
        if (file->f_op->open)
@@ -174,6 +179,22 @@ static struct file_operations snd_fops =
        .open =         snd_open
 };
 
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+static int snd_find_free_minor(void)
+{
+       int minor;
+
+       for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
+               /* skip minors still used statically for autoloading devices */
+               if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL ||
+                   minor == SNDRV_MINOR_SEQUENCER)
+                       continue;
+               if (!snd_minors[minor])
+                       return minor;
+       }
+       return -EBUSY;
+}
+#else
 static int snd_kernel_minor(int type, struct snd_card *card, int dev)
 {
        int minor;
@@ -200,6 +221,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
        snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
        return minor;
 }
+#endif
 
 /**
  * snd_register_device - Register the ALSA device file for the card
@@ -219,12 +241,10 @@ int snd_register_device(int type, struct snd_card *card, int dev,
                        struct file_operations *f_ops, void *private_data,
                        const char *name)
 {
-       int minor = snd_kernel_minor(type, card, dev);
+       int minor;
        struct snd_minor *preg;
        struct device *device = NULL;
 
-       if (minor < 0)
-               return minor;
        snd_assert(name, return -EINVAL);
        preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL);
        if (preg == NULL)
@@ -236,10 +256,17 @@ int snd_register_device(int type, struct snd_card *card, int dev,
        preg->private_data = private_data;
        strcpy(preg->name, name);
        down(&sound_mutex);
-       if (snd_minors[minor]) {
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+       minor = snd_find_free_minor();
+#else
+       minor = snd_kernel_minor(type, card, dev);
+       if (minor >= 0 && snd_minors[minor])
+               minor = -EBUSY;
+#endif
+       if (minor < 0) {
                up(&sound_mutex);
                kfree(preg);
-               return -EBUSY;
+               return minor;
        }
        snd_minors[minor] = preg;
        if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit)