Commit 332682b1 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Jaroslav Kysela

[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: default avatarClemens Ladisch <clemens@ladisch.de>
parent f87135f5
...@@ -26,18 +26,20 @@ ...@@ -26,18 +26,20 @@
#define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f) #define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f)
#define SNDRV_MINOR(card, dev) (((card) << 5) | (dev)) #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_GLOBAL 1 /* 1 */
#define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) #define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32)
#define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 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_HWDEP 4 /* 4 - 7 */
#define SNDRV_MINOR_HWDEPS 4
#define SNDRV_MINOR_RAWMIDI 8 /* 8 - 15 */ #define SNDRV_MINOR_RAWMIDI 8 /* 8 - 15 */
#define SNDRV_MINOR_RAWMIDIS 8
#define SNDRV_MINOR_PCM_PLAYBACK 16 /* 16 - 23 */ #define SNDRV_MINOR_PCM_PLAYBACK 16 /* 16 - 23 */
#define SNDRV_MINOR_PCM_CAPTURE 24 /* 24 - 31 */ #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_CONTROL SNDRV_MINOR_CONTROL
#define SNDRV_DEVICE_TYPE_HWDEP SNDRV_MINOR_HWDEP #define SNDRV_DEVICE_TYPE_HWDEP SNDRV_MINOR_HWDEP
#define SNDRV_DEVICE_TYPE_RAWMIDI SNDRV_MINOR_RAWMIDI #define SNDRV_DEVICE_TYPE_RAWMIDI SNDRV_MINOR_RAWMIDI
...@@ -46,6 +48,25 @@ ...@@ -46,6 +48,25 @@
#define SNDRV_DEVICE_TYPE_SEQUENCER SNDRV_MINOR_SEQUENCER #define SNDRV_DEVICE_TYPE_SEQUENCER SNDRV_MINOR_SEQUENCER
#define SNDRV_DEVICE_TYPE_TIMER SNDRV_MINOR_TIMER #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 #ifdef CONFIG_SND_OSSEMUL
#define SNDRV_MINOR_OSS_DEVICES 16 #define SNDRV_MINOR_OSS_DEVICES 16
......
...@@ -111,6 +111,17 @@ config SND_SEQ_RTCTIMER_DEFAULT ...@@ -111,6 +111,17 @@ config SND_SEQ_RTCTIMER_DEFAULT
If in doubt, say Y. 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 config SND_VERBOSE_PRINTK
bool "Verbose printk" bool "Verbose printk"
depends on SND depends on SND
......
...@@ -133,29 +133,34 @@ void *snd_lookup_minor_data(unsigned int minor, int type) ...@@ -133,29 +133,34 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
static int snd_open(struct inode *inode, struct file *file) static int snd_open(struct inode *inode, struct file *file)
{ {
int minor = iminor(inode); unsigned int minor = iminor(inode);
int card = SNDRV_MINOR_CARD(minor);
int dev = SNDRV_MINOR_DEVICE(minor);
struct snd_minor *mptr = NULL; struct snd_minor *mptr = NULL;
struct file_operations *old_fops; struct file_operations *old_fops;
int err = 0; int err = 0;
if (dev != SNDRV_MINOR_GLOBAL) { if (minor > ARRAY_SIZE(snd_minors))
if (snd_cards[card] == NULL) {
#ifdef CONFIG_KMOD
snd_request_card(card);
if (snd_cards[card] == NULL)
#endif
return -ENODEV; return -ENODEV;
} mptr = snd_minors[minor];
} else { if (mptr == NULL) {
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
if ((mptr = snd_minors[minor]) == NULL) int dev = SNDRV_MINOR_DEVICE(minor);
if (dev == SNDRV_MINOR_CONTROL) {
/* /dev/aloadC? */
int card = SNDRV_MINOR_CARD(minor);
if (snd_cards[card] == NULL)
snd_request_card(card);
} else if (dev == SNDRV_MINOR_GLOBAL) {
/* /dev/aloadSEQ */
snd_request_other(minor); snd_request_other(minor);
#endif
} }
if (mptr == NULL && (mptr = snd_minors[minor]) == NULL) #ifndef CONFIG_SND_DYNAMIC_MINORS
/* /dev/snd/{controlC?,seq} */
mptr = snd_minors[minor];
if (mptr == NULL)
#endif
#endif
return -ENODEV; return -ENODEV;
}
old_fops = file->f_op; old_fops = file->f_op;
file->f_op = fops_get(mptr->f_ops); file->f_op = fops_get(mptr->f_ops);
if (file->f_op->open) if (file->f_op->open)
...@@ -174,6 +179,22 @@ static struct file_operations snd_fops = ...@@ -174,6 +179,22 @@ static struct file_operations snd_fops =
.open = snd_open .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) static int snd_kernel_minor(int type, struct snd_card *card, int dev)
{ {
int minor; int minor;
...@@ -200,6 +221,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) ...@@ -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); snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
return minor; return minor;
} }
#endif
/** /**
* snd_register_device - Register the ALSA device file for the card * 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, ...@@ -219,12 +241,10 @@ int snd_register_device(int type, struct snd_card *card, int dev,
struct file_operations *f_ops, void *private_data, struct file_operations *f_ops, void *private_data,
const char *name) const char *name)
{ {
int minor = snd_kernel_minor(type, card, dev); int minor;
struct snd_minor *preg; struct snd_minor *preg;
struct device *device = NULL; struct device *device = NULL;
if (minor < 0)
return minor;
snd_assert(name, return -EINVAL); snd_assert(name, return -EINVAL);
preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL); preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL);
if (preg == NULL) if (preg == NULL)
...@@ -236,10 +256,17 @@ int snd_register_device(int type, struct snd_card *card, int dev, ...@@ -236,10 +256,17 @@ int snd_register_device(int type, struct snd_card *card, int dev,
preg->private_data = private_data; preg->private_data = private_data;
strcpy(preg->name, name); strcpy(preg->name, name);
down(&sound_mutex); 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); up(&sound_mutex);
kfree(preg); kfree(preg);
return -EBUSY; return minor;
} }
snd_minors[minor] = preg; snd_minors[minor] = preg;
if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit) if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment