1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Advanced Linux Sound Architecture
4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
7 #include <linux/init.h>
8 #include <linux/slab.h>
9 #include <linux/time.h>
10 #include <linux/device.h>
11 #include <linux/module.h>
12 #include <sound/core.h>
13 #include <sound/minors.h>
14 #include <sound/info.h>
15 #include <sound/control.h>
16 #include <sound/initval.h>
17 #include <linux/kmod.h>
18 #include <linux/mutex.h>
20 static int major
= CONFIG_SND_MAJOR
;
22 EXPORT_SYMBOL(snd_major
);
24 static int cards_limit
= 1;
26 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
27 MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
28 MODULE_LICENSE("GPL");
29 module_param(major
, int, 0444);
30 MODULE_PARM_DESC(major
, "Major # for sound driver.");
31 module_param(cards_limit
, int, 0444);
32 MODULE_PARM_DESC(cards_limit
, "Count of auto-loadable soundcards.");
33 MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR
);
35 /* this one holds the actual max. card number currently available.
36 * as default, it's identical with cards_limit option. when more
37 * modules are loaded manually, this limit number increases, too.
40 EXPORT_SYMBOL(snd_ecards_limit
);
42 static struct snd_minor
*snd_minors
[SNDRV_OS_MINORS
];
43 static DEFINE_MUTEX(sound_mutex
);
48 * snd_request_card - try to load the card module
49 * @card: the card number
51 * Tries to load the module "snd-card-X" for the given card number
52 * via request_module. Returns immediately if already loaded.
54 void snd_request_card(int card
)
56 if (snd_card_locked(card
))
58 if (card
< 0 || card
>= cards_limit
)
60 request_module("snd-card-%i", card
);
62 EXPORT_SYMBOL(snd_request_card
);
64 static void snd_request_other(int minor
)
69 case SNDRV_MINOR_SEQUENCER
: str
= "snd-seq"; break;
70 case SNDRV_MINOR_TIMER
: str
= "snd-timer"; break;
76 #endif /* modular kernel */
79 * snd_lookup_minor_data - get user data of a registered device
80 * @minor: the minor number
81 * @type: device type (SNDRV_DEVICE_TYPE_XXX)
83 * Checks that a minor device with the specified type is registered, and returns
84 * its user data pointer.
86 * This function increments the reference counter of the card instance
87 * if an associated instance with the given minor number and type is found.
88 * The caller must call snd_card_unref() appropriately later.
90 * Return: The user data pointer if the specified device is found. %NULL
93 void *snd_lookup_minor_data(unsigned int minor
, int type
)
95 struct snd_minor
*mreg
;
98 if (minor
>= ARRAY_SIZE(snd_minors
))
100 mutex_lock(&sound_mutex
);
101 mreg
= snd_minors
[minor
];
102 if (mreg
&& mreg
->type
== type
) {
103 private_data
= mreg
->private_data
;
104 if (private_data
&& mreg
->card_ptr
)
105 get_device(&mreg
->card_ptr
->card_dev
);
108 mutex_unlock(&sound_mutex
);
111 EXPORT_SYMBOL(snd_lookup_minor_data
);
113 #ifdef CONFIG_MODULES
114 static struct snd_minor
*autoload_device(unsigned int minor
)
117 mutex_unlock(&sound_mutex
); /* release lock temporarily */
118 dev
= SNDRV_MINOR_DEVICE(minor
);
119 if (dev
== SNDRV_MINOR_CONTROL
) {
121 int card
= SNDRV_MINOR_CARD(minor
);
122 struct snd_card
*ref
= snd_card_ref(card
);
124 snd_request_card(card
);
127 } else if (dev
== SNDRV_MINOR_GLOBAL
) {
129 snd_request_other(minor
);
131 mutex_lock(&sound_mutex
); /* reacuire lock */
132 return snd_minors
[minor
];
134 #else /* !CONFIG_MODULES */
135 #define autoload_device(minor) NULL
136 #endif /* CONFIG_MODULES */
138 static int snd_open(struct inode
*inode
, struct file
*file
)
140 unsigned int minor
= iminor(inode
);
141 struct snd_minor
*mptr
= NULL
;
142 const struct file_operations
*new_fops
;
145 if (minor
>= ARRAY_SIZE(snd_minors
))
147 mutex_lock(&sound_mutex
);
148 mptr
= snd_minors
[minor
];
150 mptr
= autoload_device(minor
);
152 mutex_unlock(&sound_mutex
);
156 new_fops
= fops_get(mptr
->f_ops
);
157 mutex_unlock(&sound_mutex
);
160 replace_fops(file
, new_fops
);
162 if (file
->f_op
->open
)
163 err
= file
->f_op
->open(inode
, file
);
167 static const struct file_operations snd_fops
=
169 .owner
= THIS_MODULE
,
171 .llseek
= noop_llseek
,
174 #ifdef CONFIG_SND_DYNAMIC_MINORS
175 static int snd_find_free_minor(int type
, struct snd_card
*card
, int dev
)
179 /* static minors for module auto loading */
180 if (type
== SNDRV_DEVICE_TYPE_SEQUENCER
)
181 return SNDRV_MINOR_SEQUENCER
;
182 if (type
== SNDRV_DEVICE_TYPE_TIMER
)
183 return SNDRV_MINOR_TIMER
;
185 for (minor
= 0; minor
< ARRAY_SIZE(snd_minors
); ++minor
) {
186 /* skip static minors still used for module auto loading */
187 if (SNDRV_MINOR_DEVICE(minor
) == SNDRV_MINOR_CONTROL
)
189 if (minor
== SNDRV_MINOR_SEQUENCER
||
190 minor
== SNDRV_MINOR_TIMER
)
192 if (!snd_minors
[minor
])
198 static int snd_find_free_minor(int type
, struct snd_card
*card
, int dev
)
203 case SNDRV_DEVICE_TYPE_SEQUENCER
:
204 case SNDRV_DEVICE_TYPE_TIMER
:
207 case SNDRV_DEVICE_TYPE_CONTROL
:
208 if (snd_BUG_ON(!card
))
210 minor
= SNDRV_MINOR(card
->number
, type
);
212 case SNDRV_DEVICE_TYPE_HWDEP
:
213 case SNDRV_DEVICE_TYPE_RAWMIDI
:
214 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK
:
215 case SNDRV_DEVICE_TYPE_PCM_CAPTURE
:
216 case SNDRV_DEVICE_TYPE_COMPRESS
:
217 if (snd_BUG_ON(!card
))
219 minor
= SNDRV_MINOR(card
->number
, type
+ dev
);
224 if (snd_BUG_ON(minor
< 0 || minor
>= SNDRV_OS_MINORS
))
226 if (snd_minors
[minor
])
233 * snd_register_device - Register the ALSA device file for the card
234 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
235 * @card: the card instance
236 * @dev: the device index
237 * @f_ops: the file operations
238 * @private_data: user pointer for f_ops->open()
239 * @device: the device to register
241 * Registers an ALSA device file for the given card.
242 * The operators have to be set in reg parameter.
244 * Return: Zero if successful, or a negative error code on failure.
246 int snd_register_device(int type
, struct snd_card
*card
, int dev
,
247 const struct file_operations
*f_ops
,
248 void *private_data
, struct device
*device
)
252 struct snd_minor
*preg
;
254 if (snd_BUG_ON(!device
))
257 preg
= kmalloc(sizeof *preg
, GFP_KERNEL
);
261 preg
->card
= card
? card
->number
: -1;
264 preg
->private_data
= private_data
;
265 preg
->card_ptr
= card
;
266 mutex_lock(&sound_mutex
);
267 minor
= snd_find_free_minor(type
, card
, dev
);
274 device
->devt
= MKDEV(major
, minor
);
275 err
= device_add(device
);
279 snd_minors
[minor
] = preg
;
281 mutex_unlock(&sound_mutex
);
286 EXPORT_SYMBOL(snd_register_device
);
289 * snd_unregister_device - unregister the device on the given card
290 * @dev: the device instance
292 * Unregisters the device file already registered via
293 * snd_register_device().
295 * Return: Zero if successful, or a negative error code on failure.
297 int snd_unregister_device(struct device
*dev
)
300 struct snd_minor
*preg
;
302 mutex_lock(&sound_mutex
);
303 for (minor
= 0; minor
< ARRAY_SIZE(snd_minors
); ++minor
) {
304 preg
= snd_minors
[minor
];
305 if (preg
&& preg
->dev
== dev
) {
306 snd_minors
[minor
] = NULL
;
312 mutex_unlock(&sound_mutex
);
313 if (minor
>= ARRAY_SIZE(snd_minors
))
317 EXPORT_SYMBOL(snd_unregister_device
);
319 #ifdef CONFIG_SND_PROC_FS
323 static const char *snd_device_type_name(int type
)
326 case SNDRV_DEVICE_TYPE_CONTROL
:
328 case SNDRV_DEVICE_TYPE_HWDEP
:
329 return "hardware dependent";
330 case SNDRV_DEVICE_TYPE_RAWMIDI
:
332 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK
:
333 return "digital audio playback";
334 case SNDRV_DEVICE_TYPE_PCM_CAPTURE
:
335 return "digital audio capture";
336 case SNDRV_DEVICE_TYPE_SEQUENCER
:
338 case SNDRV_DEVICE_TYPE_TIMER
:
345 static void snd_minor_info_read(struct snd_info_entry
*entry
, struct snd_info_buffer
*buffer
)
348 struct snd_minor
*mptr
;
350 mutex_lock(&sound_mutex
);
351 for (minor
= 0; minor
< SNDRV_OS_MINORS
; ++minor
) {
352 if (!(mptr
= snd_minors
[minor
]))
354 if (mptr
->card
>= 0) {
355 if (mptr
->device
>= 0)
356 snd_iprintf(buffer
, "%3i: [%2i-%2i]: %s\n",
357 minor
, mptr
->card
, mptr
->device
,
358 snd_device_type_name(mptr
->type
));
360 snd_iprintf(buffer
, "%3i: [%2i] : %s\n",
362 snd_device_type_name(mptr
->type
));
364 snd_iprintf(buffer
, "%3i: : %s\n", minor
,
365 snd_device_type_name(mptr
->type
));
367 mutex_unlock(&sound_mutex
);
370 int __init
snd_minor_info_init(void)
372 struct snd_info_entry
*entry
;
374 entry
= snd_info_create_module_entry(THIS_MODULE
, "devices", NULL
);
377 entry
->c
.text
.read
= snd_minor_info_read
;
378 return snd_info_register(entry
); /* freed in error path */
380 #endif /* CONFIG_SND_PROC_FS */
386 static int __init
alsa_sound_init(void)
389 snd_ecards_limit
= cards_limit
;
390 if (register_chrdev(major
, "alsa", &snd_fops
)) {
391 pr_err("ALSA core: unable to register native major device number %d\n", major
);
394 if (snd_info_init() < 0) {
395 unregister_chrdev(major
, "alsa");
399 pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
404 static void __exit
alsa_sound_exit(void)
407 unregister_chrdev(major
, "alsa");
410 subsys_initcall(alsa_sound_init
);
411 module_exit(alsa_sound_exit
);