summaryrefslogtreecommitdiffstats
path: root/sound
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 /sound
parentf87135f56cb266e031f5ec081dfbde7e43f55e80 (diff)
downloadblackbird-op-linux-332682b1cd540dd7abbbbfc1905af8139e76e1b7.tar.gz
blackbird-op-linux-332682b1cd540dd7abbbbfc1905af8139e76e1b7.zip
[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>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/Kconfig11
-rw-r--r--sound/core/sound.c65
2 files changed, 57 insertions, 19 deletions
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)
OpenPOWER on IntegriCloud