diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2005-11-20 08:07:47 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:29:19 -0500 |
commit | 332682b1cd540dd7abbbbfc1905af8139e76e1b7 (patch) | |
tree | e2e858870972073b2e01f7f8d5948c187c11e2bb | |
parent | f87135f56cb266e031f5ec081dfbde7e43f55e80 (diff) |
[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.h | 29 | ||||
-rw-r--r-- | sound/core/Kconfig | 11 | ||||
-rw-r--r-- | sound/core/sound.c | 65 |
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 @@ | |||
26 | #define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f) | 26 | #define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f) |
27 | #define SNDRV_MINOR(card, dev) (((card) << 5) | (dev)) | 27 | #define SNDRV_MINOR(card, dev) (((card) << 5) | (dev)) |
28 | 28 | ||
29 | #define SNDRV_MINOR_CONTROL 0 /* 0 - 0 */ | 29 | /* these minors can still be used for autoloading devices (/dev/aload*) */ |
30 | #define SNDRV_MINOR_CONTROL 0 /* 0 */ | ||
30 | #define SNDRV_MINOR_GLOBAL 1 /* 1 */ | 31 | #define SNDRV_MINOR_GLOBAL 1 /* 1 */ |
31 | #define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) | 32 | #define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) |
32 | #define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32) | 33 | #define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32) |
34 | |||
35 | #ifndef CONFIG_SND_DYNAMIC_MINORS | ||
36 | /* 2 - 3 (reserved) */ | ||
33 | #define SNDRV_MINOR_HWDEP 4 /* 4 - 7 */ | 37 | #define SNDRV_MINOR_HWDEP 4 /* 4 - 7 */ |
34 | #define SNDRV_MINOR_HWDEPS 4 | ||
35 | #define SNDRV_MINOR_RAWMIDI 8 /* 8 - 15 */ | 38 | #define SNDRV_MINOR_RAWMIDI 8 /* 8 - 15 */ |
36 | #define SNDRV_MINOR_RAWMIDIS 8 | ||
37 | #define SNDRV_MINOR_PCM_PLAYBACK 16 /* 16 - 23 */ | 39 | #define SNDRV_MINOR_PCM_PLAYBACK 16 /* 16 - 23 */ |
38 | #define SNDRV_MINOR_PCM_CAPTURE 24 /* 24 - 31 */ | 40 | #define SNDRV_MINOR_PCM_CAPTURE 24 /* 24 - 31 */ |
39 | #define SNDRV_MINOR_PCMS 8 | ||
40 | 41 | ||
42 | /* same as first respective minor number to make minor allocation easier */ | ||
41 | #define SNDRV_DEVICE_TYPE_CONTROL SNDRV_MINOR_CONTROL | 43 | #define SNDRV_DEVICE_TYPE_CONTROL SNDRV_MINOR_CONTROL |
42 | #define SNDRV_DEVICE_TYPE_HWDEP SNDRV_MINOR_HWDEP | 44 | #define SNDRV_DEVICE_TYPE_HWDEP SNDRV_MINOR_HWDEP |
43 | #define SNDRV_DEVICE_TYPE_RAWMIDI SNDRV_MINOR_RAWMIDI | 45 | #define SNDRV_DEVICE_TYPE_RAWMIDI SNDRV_MINOR_RAWMIDI |
@@ -46,6 +48,25 @@ | |||
46 | #define SNDRV_DEVICE_TYPE_SEQUENCER SNDRV_MINOR_SEQUENCER | 48 | #define SNDRV_DEVICE_TYPE_SEQUENCER SNDRV_MINOR_SEQUENCER |
47 | #define SNDRV_DEVICE_TYPE_TIMER SNDRV_MINOR_TIMER | 49 | #define SNDRV_DEVICE_TYPE_TIMER SNDRV_MINOR_TIMER |
48 | 50 | ||
51 | #else /* CONFIG_SND_DYNAMIC_MINORS */ | ||
52 | |||
53 | enum { | ||
54 | SNDRV_DEVICE_TYPE_CONTROL, | ||
55 | SNDRV_DEVICE_TYPE_SEQUENCER, | ||
56 | SNDRV_DEVICE_TYPE_TIMER, | ||
57 | SNDRV_DEVICE_TYPE_HWDEP, | ||
58 | SNDRV_DEVICE_TYPE_RAWMIDI, | ||
59 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK, | ||
60 | SNDRV_DEVICE_TYPE_PCM_CAPTURE, | ||
61 | }; | ||
62 | |||
63 | #endif /* CONFIG_SND_DYNAMIC_MINORS */ | ||
64 | |||
65 | #define SNDRV_MINOR_HWDEPS 4 | ||
66 | #define SNDRV_MINOR_RAWMIDIS 8 | ||
67 | #define SNDRV_MINOR_PCMS 8 | ||
68 | |||
69 | |||
49 | #ifdef CONFIG_SND_OSSEMUL | 70 | #ifdef CONFIG_SND_OSSEMUL |
50 | 71 | ||
51 | #define SNDRV_MINOR_OSS_DEVICES 16 | 72 | #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 | |||
111 | 111 | ||
112 | If in doubt, say Y. | 112 | If in doubt, say Y. |
113 | 113 | ||
114 | config SND_DYNAMIC_MINORS | ||
115 | bool "Dynamic device file minor numbers (EXPERIMENTAL)" | ||
116 | depends on SND && EXPERIMENTAL | ||
117 | help | ||
118 | If you say Y here, the minor numbers of ALSA device files in | ||
119 | /dev/snd/ are allocated dynamically. This allows you to have | ||
120 | more than 8 sound cards, but requires a dynamic device file | ||
121 | system like udev. | ||
122 | |||
123 | If you are unsure about this, say N here. | ||
124 | |||
114 | config SND_VERBOSE_PRINTK | 125 | config SND_VERBOSE_PRINTK |
115 | bool "Verbose printk" | 126 | bool "Verbose printk" |
116 | depends on SND | 127 | 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) | |||
133 | 133 | ||
134 | static int snd_open(struct inode *inode, struct file *file) | 134 | static int snd_open(struct inode *inode, struct file *file) |
135 | { | 135 | { |
136 | int minor = iminor(inode); | 136 | unsigned int minor = iminor(inode); |
137 | int card = SNDRV_MINOR_CARD(minor); | ||
138 | int dev = SNDRV_MINOR_DEVICE(minor); | ||
139 | struct snd_minor *mptr = NULL; | 137 | struct snd_minor *mptr = NULL; |
140 | struct file_operations *old_fops; | 138 | struct file_operations *old_fops; |
141 | int err = 0; | 139 | int err = 0; |
142 | 140 | ||
143 | if (dev != SNDRV_MINOR_GLOBAL) { | 141 | if (minor > ARRAY_SIZE(snd_minors)) |
144 | if (snd_cards[card] == NULL) { | 142 | return -ENODEV; |
143 | mptr = snd_minors[minor]; | ||
144 | if (mptr == NULL) { | ||
145 | #ifdef CONFIG_KMOD | 145 | #ifdef CONFIG_KMOD |
146 | snd_request_card(card); | 146 | int dev = SNDRV_MINOR_DEVICE(minor); |
147 | if (dev == SNDRV_MINOR_CONTROL) { | ||
148 | /* /dev/aloadC? */ | ||
149 | int card = SNDRV_MINOR_CARD(minor); | ||
147 | if (snd_cards[card] == NULL) | 150 | if (snd_cards[card] == NULL) |
148 | #endif | 151 | snd_request_card(card); |
149 | return -ENODEV; | 152 | } else if (dev == SNDRV_MINOR_GLOBAL) { |
150 | } | 153 | /* /dev/aloadSEQ */ |
151 | } else { | ||
152 | #ifdef CONFIG_KMOD | ||
153 | if ((mptr = snd_minors[minor]) == NULL) | ||
154 | snd_request_other(minor); | 154 | snd_request_other(minor); |
155 | } | ||
156 | #ifndef CONFIG_SND_DYNAMIC_MINORS | ||
157 | /* /dev/snd/{controlC?,seq} */ | ||
158 | mptr = snd_minors[minor]; | ||
159 | if (mptr == NULL) | ||
160 | #endif | ||
155 | #endif | 161 | #endif |
162 | return -ENODEV; | ||
156 | } | 163 | } |
157 | if (mptr == NULL && (mptr = snd_minors[minor]) == NULL) | ||
158 | return -ENODEV; | ||
159 | old_fops = file->f_op; | 164 | old_fops = file->f_op; |
160 | file->f_op = fops_get(mptr->f_ops); | 165 | file->f_op = fops_get(mptr->f_ops); |
161 | if (file->f_op->open) | 166 | if (file->f_op->open) |
@@ -174,6 +179,22 @@ static struct file_operations snd_fops = | |||
174 | .open = snd_open | 179 | .open = snd_open |
175 | }; | 180 | }; |
176 | 181 | ||
182 | #ifdef CONFIG_SND_DYNAMIC_MINORS | ||
183 | static int snd_find_free_minor(void) | ||
184 | { | ||
185 | int minor; | ||
186 | |||
187 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { | ||
188 | /* skip minors still used statically for autoloading devices */ | ||
189 | if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL || | ||
190 | minor == SNDRV_MINOR_SEQUENCER) | ||
191 | continue; | ||
192 | if (!snd_minors[minor]) | ||
193 | return minor; | ||
194 | } | ||
195 | return -EBUSY; | ||
196 | } | ||
197 | #else | ||
177 | static int snd_kernel_minor(int type, struct snd_card *card, int dev) | 198 | static int snd_kernel_minor(int type, struct snd_card *card, int dev) |
178 | { | 199 | { |
179 | int minor; | 200 | int minor; |
@@ -200,6 +221,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) | |||
200 | snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL); | 221 | snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL); |
201 | return minor; | 222 | return minor; |
202 | } | 223 | } |
224 | #endif | ||
203 | 225 | ||
204 | /** | 226 | /** |
205 | * snd_register_device - Register the ALSA device file for the card | 227 | * 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 | struct file_operations *f_ops, void *private_data, | 241 | struct file_operations *f_ops, void *private_data, |
220 | const char *name) | 242 | const char *name) |
221 | { | 243 | { |
222 | int minor = snd_kernel_minor(type, card, dev); | 244 | int minor; |
223 | struct snd_minor *preg; | 245 | struct snd_minor *preg; |
224 | struct device *device = NULL; | 246 | struct device *device = NULL; |
225 | 247 | ||
226 | if (minor < 0) | ||
227 | return minor; | ||
228 | snd_assert(name, return -EINVAL); | 248 | snd_assert(name, return -EINVAL); |
229 | preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL); | 249 | preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL); |
230 | if (preg == NULL) | 250 | if (preg == NULL) |
@@ -236,10 +256,17 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
236 | preg->private_data = private_data; | 256 | preg->private_data = private_data; |
237 | strcpy(preg->name, name); | 257 | strcpy(preg->name, name); |
238 | down(&sound_mutex); | 258 | down(&sound_mutex); |
239 | if (snd_minors[minor]) { | 259 | #ifdef CONFIG_SND_DYNAMIC_MINORS |
260 | minor = snd_find_free_minor(); | ||
261 | #else | ||
262 | minor = snd_kernel_minor(type, card, dev); | ||
263 | if (minor >= 0 && snd_minors[minor]) | ||
264 | minor = -EBUSY; | ||
265 | #endif | ||
266 | if (minor < 0) { | ||
240 | up(&sound_mutex); | 267 | up(&sound_mutex); |
241 | kfree(preg); | 268 | kfree(preg); |
242 | return -EBUSY; | 269 | return minor; |
243 | } | 270 | } |
244 | snd_minors[minor] = preg; | 271 | snd_minors[minor] = preg; |
245 | if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit) | 272 | if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit) |