summary refs log tree commit diff
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2005-11-20 14:07:47 +0100
committerJaroslav Kysela <perex@suse.cz>2006-01-03 12:29:19 +0100
commit332682b1cd540dd7abbbbfc1905af8139e76e1b7 (patch)
treee2e858870972073b2e01f7f8d5948c187c11e2bb
parentf87135f56cb266e031f5ec081dfbde7e43f55e80 (diff)
downloadlinux-332682b1cd540dd7abbbbfc1905af8139e76e1b7.tar.gz
[ALSA] dynamic minors (4/6): dynamic minor number allocation
Modules: ALSA Core,ALSA Minor Numbers

Add an option to allocate device file minor numbers dynamically.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
-rw-r--r--include/sound/minors.h29
-rw-r--r--sound/core/Kconfig11
-rw-r--r--sound/core/sound.c65
3 files changed, 82 insertions, 23 deletions
diff --git a/include/sound/minors.h b/include/sound/minors.h
index a17b5c9961bb..46bcd2023ed8 100644
--- a/include/sound/minors.h
+++ b/include/sound/minors.h
@@ -26,18 +26,20 @@
 #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
@@ -46,6 +48,25 @@
 #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
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b46efff2e4c4..83cbe20c9c9e 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -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
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 1e5eca546925..5e22283078fc 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -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)