Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/core/sound.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Advanced Linux Sound Architecture
4
* Copyright (c) by Jaroslav Kysela <[email protected]>
5
*/
6
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 <linux/debugfs.h>
13
#include <sound/core.h>
14
#include <sound/minors.h>
15
#include <sound/info.h>
16
#include <sound/control.h>
17
#include <sound/initval.h>
18
#include <linux/kmod.h>
19
#include <linux/mutex.h>
20
21
static int major = CONFIG_SND_MAJOR;
22
int snd_major;
23
EXPORT_SYMBOL(snd_major);
24
25
static int cards_limit = 1;
26
27
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
28
MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
29
MODULE_LICENSE("GPL");
30
module_param(major, int, 0444);
31
MODULE_PARM_DESC(major, "Major # for sound driver.");
32
module_param(cards_limit, int, 0444);
33
MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
34
MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
35
36
/* this one holds the actual max. card number currently available.
37
* as default, it's identical with cards_limit option. when more
38
* modules are loaded manually, this limit number increases, too.
39
*/
40
int snd_ecards_limit;
41
EXPORT_SYMBOL(snd_ecards_limit);
42
43
#ifdef CONFIG_SND_DEBUG
44
struct dentry *sound_debugfs_root;
45
EXPORT_SYMBOL_GPL(sound_debugfs_root);
46
#endif
47
48
static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
49
static DEFINE_MUTEX(sound_mutex);
50
51
#ifdef CONFIG_MODULES
52
53
/**
54
* snd_request_card - try to load the card module
55
* @card: the card number
56
*
57
* Tries to load the module "snd-card-X" for the given card number
58
* via request_module. Returns immediately if already loaded.
59
*/
60
void snd_request_card(int card)
61
{
62
if (snd_card_locked(card))
63
return;
64
if (card < 0 || card >= cards_limit)
65
return;
66
request_module("snd-card-%i", card);
67
}
68
EXPORT_SYMBOL(snd_request_card);
69
70
static void snd_request_other(int minor)
71
{
72
char *str;
73
74
switch (minor) {
75
case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break;
76
case SNDRV_MINOR_TIMER: str = "snd-timer"; break;
77
default: return;
78
}
79
request_module(str);
80
}
81
82
#endif /* modular kernel */
83
84
/**
85
* snd_lookup_minor_data - get user data of a registered device
86
* @minor: the minor number
87
* @type: device type (SNDRV_DEVICE_TYPE_XXX)
88
*
89
* Checks that a minor device with the specified type is registered, and returns
90
* its user data pointer.
91
*
92
* This function increments the reference counter of the card instance
93
* if an associated instance with the given minor number and type is found.
94
* The caller must call snd_card_unref() appropriately later.
95
*
96
* Return: The user data pointer if the specified device is found. %NULL
97
* otherwise.
98
*/
99
void *snd_lookup_minor_data(unsigned int minor, int type)
100
{
101
struct snd_minor *mreg;
102
void *private_data;
103
104
if (minor >= ARRAY_SIZE(snd_minors))
105
return NULL;
106
guard(mutex)(&sound_mutex);
107
mreg = snd_minors[minor];
108
if (mreg && mreg->type == type) {
109
private_data = mreg->private_data;
110
if (private_data && mreg->card_ptr)
111
get_device(&mreg->card_ptr->card_dev);
112
} else
113
private_data = NULL;
114
return private_data;
115
}
116
EXPORT_SYMBOL(snd_lookup_minor_data);
117
118
#ifdef CONFIG_MODULES
119
static struct snd_minor *autoload_device(unsigned int minor)
120
{
121
int dev;
122
mutex_unlock(&sound_mutex); /* release lock temporarily */
123
dev = SNDRV_MINOR_DEVICE(minor);
124
if (dev == SNDRV_MINOR_CONTROL) {
125
/* /dev/aloadC? */
126
int card = SNDRV_MINOR_CARD(minor);
127
struct snd_card *ref = snd_card_ref(card);
128
if (!ref)
129
snd_request_card(card);
130
else
131
snd_card_unref(ref);
132
} else if (dev == SNDRV_MINOR_GLOBAL) {
133
/* /dev/aloadSEQ */
134
snd_request_other(minor);
135
}
136
mutex_lock(&sound_mutex); /* reacquire lock */
137
return snd_minors[minor];
138
}
139
#else /* !CONFIG_MODULES */
140
#define autoload_device(minor) NULL
141
#endif /* CONFIG_MODULES */
142
143
static int snd_open(struct inode *inode, struct file *file)
144
{
145
unsigned int minor = iminor(inode);
146
struct snd_minor *mptr = NULL;
147
const struct file_operations *new_fops;
148
int err = 0;
149
150
if (minor >= ARRAY_SIZE(snd_minors))
151
return -ENODEV;
152
scoped_guard(mutex, &sound_mutex) {
153
mptr = snd_minors[minor];
154
if (mptr == NULL) {
155
mptr = autoload_device(minor);
156
if (!mptr)
157
return -ENODEV;
158
}
159
new_fops = fops_get(mptr->f_ops);
160
}
161
if (!new_fops)
162
return -ENODEV;
163
replace_fops(file, new_fops);
164
165
if (file->f_op->open)
166
err = file->f_op->open(inode, file);
167
return err;
168
}
169
170
static const struct file_operations snd_fops =
171
{
172
.owner = THIS_MODULE,
173
.open = snd_open,
174
.llseek = noop_llseek,
175
};
176
177
#ifdef CONFIG_SND_DYNAMIC_MINORS
178
static int snd_find_free_minor(int type, struct snd_card *card, int dev)
179
{
180
int minor;
181
182
/* static minors for module auto loading */
183
if (type == SNDRV_DEVICE_TYPE_SEQUENCER)
184
return SNDRV_MINOR_SEQUENCER;
185
if (type == SNDRV_DEVICE_TYPE_TIMER)
186
return SNDRV_MINOR_TIMER;
187
188
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
189
/* skip static minors still used for module auto loading */
190
if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL)
191
continue;
192
if (minor == SNDRV_MINOR_SEQUENCER ||
193
minor == SNDRV_MINOR_TIMER)
194
continue;
195
if (!snd_minors[minor])
196
return minor;
197
}
198
return -EBUSY;
199
}
200
#else
201
static int snd_find_free_minor(int type, struct snd_card *card, int dev)
202
{
203
int minor;
204
205
switch (type) {
206
case SNDRV_DEVICE_TYPE_SEQUENCER:
207
case SNDRV_DEVICE_TYPE_TIMER:
208
minor = type;
209
break;
210
case SNDRV_DEVICE_TYPE_CONTROL:
211
if (snd_BUG_ON(!card))
212
return -EINVAL;
213
minor = SNDRV_MINOR(card->number, type);
214
break;
215
case SNDRV_DEVICE_TYPE_HWDEP:
216
case SNDRV_DEVICE_TYPE_RAWMIDI:
217
case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
218
case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
219
case SNDRV_DEVICE_TYPE_COMPRESS:
220
if (snd_BUG_ON(!card))
221
return -EINVAL;
222
minor = SNDRV_MINOR(card->number, type + dev);
223
break;
224
default:
225
return -EINVAL;
226
}
227
if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
228
return -EINVAL;
229
if (snd_minors[minor])
230
return -EBUSY;
231
return minor;
232
}
233
#endif
234
235
/**
236
* snd_register_device - Register the ALSA device file for the card
237
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
238
* @card: the card instance
239
* @dev: the device index
240
* @f_ops: the file operations
241
* @private_data: user pointer for f_ops->open()
242
* @device: the device to register
243
*
244
* Registers an ALSA device file for the given card.
245
* The operators have to be set in reg parameter.
246
*
247
* Return: Zero if successful, or a negative error code on failure.
248
*/
249
int snd_register_device(int type, struct snd_card *card, int dev,
250
const struct file_operations *f_ops,
251
void *private_data, struct device *device)
252
{
253
int minor;
254
int err = 0;
255
struct snd_minor *preg;
256
257
if (snd_BUG_ON(!device))
258
return -EINVAL;
259
260
preg = kmalloc(sizeof *preg, GFP_KERNEL);
261
if (preg == NULL)
262
return -ENOMEM;
263
preg->type = type;
264
preg->card = card ? card->number : -1;
265
preg->device = dev;
266
preg->f_ops = f_ops;
267
preg->private_data = private_data;
268
preg->card_ptr = card;
269
guard(mutex)(&sound_mutex);
270
minor = snd_find_free_minor(type, card, dev);
271
if (minor < 0) {
272
err = minor;
273
goto error;
274
}
275
276
preg->dev = device;
277
device->devt = MKDEV(major, minor);
278
err = device_add(device);
279
if (err < 0)
280
goto error;
281
282
snd_minors[minor] = preg;
283
error:
284
if (err < 0)
285
kfree(preg);
286
return err;
287
}
288
EXPORT_SYMBOL(snd_register_device);
289
290
/**
291
* snd_unregister_device - unregister the device on the given card
292
* @dev: the device instance
293
*
294
* Unregisters the device file already registered via
295
* snd_register_device().
296
*
297
* Return: Zero if successful, or a negative error code on failure.
298
*/
299
int snd_unregister_device(struct device *dev)
300
{
301
int minor;
302
struct snd_minor *preg;
303
304
guard(mutex)(&sound_mutex);
305
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
306
preg = snd_minors[minor];
307
if (preg && preg->dev == dev) {
308
snd_minors[minor] = NULL;
309
device_del(dev);
310
kfree(preg);
311
break;
312
}
313
}
314
if (minor >= ARRAY_SIZE(snd_minors))
315
return -ENOENT;
316
return 0;
317
}
318
EXPORT_SYMBOL(snd_unregister_device);
319
320
#ifdef CONFIG_SND_PROC_FS
321
/*
322
* INFO PART
323
*/
324
static const char *snd_device_type_name(int type)
325
{
326
switch (type) {
327
case SNDRV_DEVICE_TYPE_CONTROL:
328
return "control";
329
case SNDRV_DEVICE_TYPE_HWDEP:
330
return "hardware dependent";
331
case SNDRV_DEVICE_TYPE_RAWMIDI:
332
return "raw midi";
333
case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
334
return "digital audio playback";
335
case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
336
return "digital audio capture";
337
case SNDRV_DEVICE_TYPE_SEQUENCER:
338
return "sequencer";
339
case SNDRV_DEVICE_TYPE_TIMER:
340
return "timer";
341
case SNDRV_DEVICE_TYPE_COMPRESS:
342
return "compress";
343
default:
344
return "?";
345
}
346
}
347
348
static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
349
{
350
int minor;
351
struct snd_minor *mptr;
352
353
guard(mutex)(&sound_mutex);
354
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
355
mptr = snd_minors[minor];
356
if (!mptr)
357
continue;
358
if (mptr->card >= 0) {
359
if (mptr->device >= 0)
360
snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n",
361
minor, mptr->card, mptr->device,
362
snd_device_type_name(mptr->type));
363
else
364
snd_iprintf(buffer, "%3i: [%2i] : %s\n",
365
minor, mptr->card,
366
snd_device_type_name(mptr->type));
367
} else
368
snd_iprintf(buffer, "%3i: : %s\n", minor,
369
snd_device_type_name(mptr->type));
370
}
371
}
372
373
int __init snd_minor_info_init(void)
374
{
375
struct snd_info_entry *entry;
376
377
entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
378
if (!entry)
379
return -ENOMEM;
380
entry->c.text.read = snd_minor_info_read;
381
return snd_info_register(entry); /* freed in error path */
382
}
383
#endif /* CONFIG_SND_PROC_FS */
384
385
/*
386
* INIT PART
387
*/
388
389
static int __init alsa_sound_init(void)
390
{
391
snd_major = major;
392
snd_ecards_limit = cards_limit;
393
if (register_chrdev(major, "alsa", &snd_fops)) {
394
pr_err("ALSA core: unable to register native major device number %d\n", major);
395
return -EIO;
396
}
397
if (snd_info_init() < 0) {
398
unregister_chrdev(major, "alsa");
399
return -ENOMEM;
400
}
401
402
#ifdef CONFIG_SND_DEBUG
403
sound_debugfs_root = debugfs_create_dir("sound", NULL);
404
#endif
405
#ifndef MODULE
406
pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
407
#endif
408
return 0;
409
}
410
411
static void __exit alsa_sound_exit(void)
412
{
413
#ifdef CONFIG_SND_DEBUG
414
debugfs_remove(sound_debugfs_root);
415
#endif
416
snd_info_done();
417
unregister_chrdev(major, "alsa");
418
}
419
420
subsys_initcall(alsa_sound_init);
421
module_exit(alsa_sound_exit);
422
423