Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/sound_core.c
26242 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Sound core. This file is composed of two parts. sound_class
4
* which is common to both OSS and ALSA and OSS sound core which
5
* is used OSS or emulation of it.
6
*/
7
8
/*
9
* First, the common part.
10
*/
11
#include <linux/module.h>
12
#include <linux/device.h>
13
#include <linux/err.h>
14
#include <linux/kdev_t.h>
15
#include <linux/major.h>
16
#include <sound/core.h>
17
18
#ifdef CONFIG_SOUND_OSS_CORE
19
static int __init init_oss_soundcore(void);
20
static void cleanup_oss_soundcore(void);
21
#else
22
static inline int init_oss_soundcore(void) { return 0; }
23
static inline void cleanup_oss_soundcore(void) { }
24
#endif
25
26
MODULE_DESCRIPTION("Core sound module");
27
MODULE_AUTHOR("Alan Cox");
28
MODULE_LICENSE("GPL");
29
30
static char *sound_devnode(const struct device *dev, umode_t *mode)
31
{
32
if (MAJOR(dev->devt) == SOUND_MAJOR)
33
return NULL;
34
return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
35
}
36
37
const struct class sound_class = {
38
.name = "sound",
39
.devnode = sound_devnode,
40
};
41
EXPORT_SYMBOL(sound_class);
42
43
static int __init init_soundcore(void)
44
{
45
int rc;
46
47
rc = init_oss_soundcore();
48
if (rc)
49
return rc;
50
51
rc = class_register(&sound_class);
52
if (rc) {
53
cleanup_oss_soundcore();
54
return rc;
55
}
56
57
return 0;
58
}
59
60
static void __exit cleanup_soundcore(void)
61
{
62
cleanup_oss_soundcore();
63
class_unregister(&sound_class);
64
}
65
66
subsys_initcall(init_soundcore);
67
module_exit(cleanup_soundcore);
68
69
70
#ifdef CONFIG_SOUND_OSS_CORE
71
/*
72
* OSS sound core handling. Breaks out sound functions to submodules
73
*
74
* Author: Alan Cox <[email protected]>
75
*
76
* Fixes:
77
*
78
* --------------------
79
*
80
* Top level handler for the sound subsystem. Various devices can
81
* plug into this. The fact they don't all go via OSS doesn't mean
82
* they don't have to implement the OSS API. There is a lot of logic
83
* to keeping much of the OSS weight out of the code in a compatibility
84
* module, but it's up to the driver to rember to load it...
85
*
86
* The code provides a set of functions for registration of devices
87
* by type. This is done rather than providing a single call so that
88
* we can hide any future changes in the internals (eg when we go to
89
* 32bit dev_t) from the modules and their interface.
90
*
91
* Secondly we need to allocate the dsp, dsp16 and audio devices as
92
* one. Thus we misuse the chains a bit to simplify this.
93
*
94
* Thirdly to make it more fun and for 2.3.x and above we do all
95
* of this using fine grained locking.
96
*
97
* FIXME: we have to resolve modules and fine grained load/unload
98
* locking at some point in 2.3.x.
99
*/
100
101
#include <linux/init.h>
102
#include <linux/slab.h>
103
#include <linux/types.h>
104
#include <linux/kernel.h>
105
#include <linux/sound.h>
106
#include <linux/kmod.h>
107
108
#define SOUND_STEP 16
109
110
struct sound_unit
111
{
112
int unit_minor;
113
const struct file_operations *unit_fops;
114
struct sound_unit *next;
115
char name[32];
116
};
117
118
/*
119
* By default, OSS sound_core claims full legacy minor range (0-255)
120
* of SOUND_MAJOR to trap open attempts to any sound minor and
121
* requests modules using custom sound-slot/service-* module aliases.
122
* The only benefit of doing this is allowing use of custom module
123
* aliases instead of the standard char-major-* ones. This behavior
124
* prevents alternative OSS implementation and is scheduled to be
125
* removed.
126
*
127
* CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel
128
* parameter are added to allow distros and developers to try and
129
* switch to alternative implementations without needing to rebuild
130
* the kernel in the meantime. If preclaim_oss is non-zero, the
131
* kernel will behave the same as before. All SOUND_MAJOR minors are
132
* preclaimed and the custom module aliases along with standard chrdev
133
* ones are emitted if a missing device is opened. If preclaim_oss is
134
* zero, sound_core only grabs what's actually in use and for missing
135
* devices only the standard chrdev aliases are requested.
136
*
137
* All these clutters are scheduled to be removed along with
138
* sound-slot/service-* module aliases.
139
*/
140
static int preclaim_oss = IS_ENABLED(CONFIG_SOUND_OSS_CORE_PRECLAIM);
141
142
module_param(preclaim_oss, int, 0444);
143
144
static int soundcore_open(struct inode *, struct file *);
145
146
static const struct file_operations soundcore_fops =
147
{
148
/* We must have an owner or the module locking fails */
149
.owner = THIS_MODULE,
150
.open = soundcore_open,
151
.llseek = noop_llseek,
152
};
153
154
/*
155
* Low level list operator. Scan the ordered list, find a hole and
156
* join into it. Called with the lock asserted
157
*/
158
159
static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
160
{
161
int n=low;
162
163
if (index < 0) { /* first free */
164
165
while (*list && (*list)->unit_minor<n)
166
list=&((*list)->next);
167
168
while(n<top)
169
{
170
/* Found a hole ? */
171
if(*list==NULL || (*list)->unit_minor>n)
172
break;
173
list=&((*list)->next);
174
n+=SOUND_STEP;
175
}
176
177
if(n>=top)
178
return -ENOENT;
179
} else {
180
n = low+(index*16);
181
while (*list) {
182
if ((*list)->unit_minor==n)
183
return -EBUSY;
184
if ((*list)->unit_minor>n)
185
break;
186
list=&((*list)->next);
187
}
188
}
189
190
/*
191
* Fill it in
192
*/
193
194
s->unit_minor=n;
195
s->unit_fops=fops;
196
197
/*
198
* Link it
199
*/
200
201
s->next=*list;
202
*list=s;
203
204
205
return n;
206
}
207
208
/*
209
* Remove a node from the chain. Called with the lock asserted
210
*/
211
212
static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
213
{
214
while(*list)
215
{
216
struct sound_unit *p=*list;
217
if(p->unit_minor==unit)
218
{
219
*list=p->next;
220
return p;
221
}
222
list=&(p->next);
223
}
224
printk(KERN_ERR "Sound device %d went missing!\n", unit);
225
return NULL;
226
}
227
228
/*
229
* This lock guards the sound loader list.
230
*/
231
232
static DEFINE_SPINLOCK(sound_loader_lock);
233
234
/*
235
* Allocate the controlling structure and add it to the sound driver
236
* list. Acquires locks as needed
237
*/
238
239
static int sound_insert_unit(struct sound_unit **list, const struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
240
{
241
struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
242
int r;
243
244
if (!s)
245
return -ENOMEM;
246
247
spin_lock(&sound_loader_lock);
248
retry:
249
r = __sound_insert_unit(s, list, fops, index, low, top);
250
spin_unlock(&sound_loader_lock);
251
252
if (r < 0)
253
goto fail;
254
else if (r < SOUND_STEP)
255
sprintf(s->name, "sound/%s", name);
256
else
257
sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
258
259
if (!preclaim_oss) {
260
/*
261
* Something else might have grabbed the minor. If
262
* first free slot is requested, rescan with @low set
263
* to the next unit; otherwise, -EBUSY.
264
*/
265
r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
266
&soundcore_fops);
267
if (r < 0) {
268
spin_lock(&sound_loader_lock);
269
__sound_remove_unit(list, s->unit_minor);
270
if (index < 0) {
271
low = s->unit_minor + SOUND_STEP;
272
goto retry;
273
}
274
spin_unlock(&sound_loader_lock);
275
r = -EBUSY;
276
goto fail;
277
}
278
}
279
280
device_create(&sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
281
NULL, "%s", s->name+6);
282
return s->unit_minor;
283
284
fail:
285
kfree(s);
286
return r;
287
}
288
289
/*
290
* Remove a unit. Acquires locks as needed. The drivers MUST have
291
* completed the removal before their file operations become
292
* invalid.
293
*/
294
295
static void sound_remove_unit(struct sound_unit **list, int unit)
296
{
297
struct sound_unit *p;
298
299
spin_lock(&sound_loader_lock);
300
p = __sound_remove_unit(list, unit);
301
spin_unlock(&sound_loader_lock);
302
if (p) {
303
if (!preclaim_oss)
304
__unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
305
p->name);
306
device_destroy(&sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
307
kfree(p);
308
}
309
}
310
311
/*
312
* Allocations
313
*
314
* 0 *16 Mixers
315
* 1 *8 Sequencers
316
* 2 *16 Midi
317
* 3 *16 DSP
318
* 4 *16 SunDSP
319
* 5 *16 DSP16
320
* 6 -- sndstat (obsolete)
321
* 7 *16 unused
322
* 8 -- alternate sequencer (see above)
323
* 9 *16 raw synthesizer access
324
* 10 *16 unused
325
* 11 *16 unused
326
* 12 *16 unused
327
* 13 *16 unused
328
* 14 *16 unused
329
* 15 *16 unused
330
*/
331
332
static struct sound_unit *chains[SOUND_STEP];
333
334
/**
335
* register_sound_special_device - register a special sound node
336
* @fops: File operations for the driver
337
* @unit: Unit number to allocate
338
* @dev: device pointer
339
*
340
* Allocate a special sound device by minor number from the sound
341
* subsystem.
342
*
343
* Return: The allocated number is returned on success. On failure,
344
* a negative error code is returned.
345
*/
346
347
int register_sound_special_device(const struct file_operations *fops, int unit,
348
struct device *dev)
349
{
350
const int chain = unit % SOUND_STEP;
351
int max_unit = 256;
352
const char *name;
353
char _name[16];
354
355
switch (chain) {
356
case 0:
357
name = "mixer";
358
break;
359
case 1:
360
name = "sequencer";
361
if (unit >= SOUND_STEP)
362
goto __unknown;
363
max_unit = unit + 1;
364
break;
365
case 2:
366
name = "midi";
367
break;
368
case 3:
369
name = "dsp";
370
break;
371
case 4:
372
name = "audio";
373
break;
374
case 5:
375
name = "dspW";
376
break;
377
case 8:
378
name = "sequencer2";
379
if (unit >= SOUND_STEP)
380
goto __unknown;
381
max_unit = unit + 1;
382
break;
383
case 9:
384
name = "dmmidi";
385
break;
386
case 10:
387
name = "dmfm";
388
break;
389
case 12:
390
name = "adsp";
391
break;
392
case 13:
393
name = "amidi";
394
break;
395
case 14:
396
name = "admmidi";
397
break;
398
default:
399
{
400
__unknown:
401
sprintf(_name, "unknown%d", chain);
402
if (unit >= SOUND_STEP)
403
strcat(_name, "-");
404
name = _name;
405
}
406
break;
407
}
408
return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
409
name, 0600, dev);
410
}
411
412
EXPORT_SYMBOL(register_sound_special_device);
413
414
int register_sound_special(const struct file_operations *fops, int unit)
415
{
416
return register_sound_special_device(fops, unit, NULL);
417
}
418
419
EXPORT_SYMBOL(register_sound_special);
420
421
/**
422
* register_sound_mixer - register a mixer device
423
* @fops: File operations for the driver
424
* @dev: Unit number to allocate
425
*
426
* Allocate a mixer device. Unit is the number of the mixer requested.
427
* Pass -1 to request the next free mixer unit.
428
*
429
* Return: On success, the allocated number is returned. On failure,
430
* a negative error code is returned.
431
*/
432
433
int register_sound_mixer(const struct file_operations *fops, int dev)
434
{
435
return sound_insert_unit(&chains[0], fops, dev, 0, 128,
436
"mixer", 0600, NULL);
437
}
438
439
EXPORT_SYMBOL(register_sound_mixer);
440
441
/*
442
* DSP's are registered as a triple. Register only one and cheat
443
* in open - see below.
444
*/
445
446
/**
447
* register_sound_dsp - register a DSP device
448
* @fops: File operations for the driver
449
* @dev: Unit number to allocate
450
*
451
* Allocate a DSP device. Unit is the number of the DSP requested.
452
* Pass -1 to request the next free DSP unit.
453
*
454
* This function allocates both the audio and dsp device entries together
455
* and will always allocate them as a matching pair - eg dsp3/audio3
456
*
457
* Return: On success, the allocated number is returned. On failure,
458
* a negative error code is returned.
459
*/
460
461
int register_sound_dsp(const struct file_operations *fops, int dev)
462
{
463
return sound_insert_unit(&chains[3], fops, dev, 3, 131,
464
"dsp", 0600, NULL);
465
}
466
467
EXPORT_SYMBOL(register_sound_dsp);
468
469
/**
470
* unregister_sound_special - unregister a special sound device
471
* @unit: unit number to allocate
472
*
473
* Release a sound device that was allocated with
474
* register_sound_special(). The unit passed is the return value from
475
* the register function.
476
*/
477
478
479
void unregister_sound_special(int unit)
480
{
481
sound_remove_unit(&chains[unit % SOUND_STEP], unit);
482
}
483
484
EXPORT_SYMBOL(unregister_sound_special);
485
486
/**
487
* unregister_sound_mixer - unregister a mixer
488
* @unit: unit number to allocate
489
*
490
* Release a sound device that was allocated with register_sound_mixer().
491
* The unit passed is the return value from the register function.
492
*/
493
494
void unregister_sound_mixer(int unit)
495
{
496
sound_remove_unit(&chains[0], unit);
497
}
498
499
EXPORT_SYMBOL(unregister_sound_mixer);
500
501
/**
502
* unregister_sound_dsp - unregister a DSP device
503
* @unit: unit number to allocate
504
*
505
* Release a sound device that was allocated with register_sound_dsp().
506
* The unit passed is the return value from the register function.
507
*
508
* Both of the allocated units are released together automatically.
509
*/
510
511
void unregister_sound_dsp(int unit)
512
{
513
sound_remove_unit(&chains[3], unit);
514
}
515
516
517
EXPORT_SYMBOL(unregister_sound_dsp);
518
519
static struct sound_unit *__look_for_unit(int chain, int unit)
520
{
521
struct sound_unit *s;
522
523
s=chains[chain];
524
while(s && s->unit_minor <= unit)
525
{
526
if(s->unit_minor==unit)
527
return s;
528
s=s->next;
529
}
530
return NULL;
531
}
532
533
static int soundcore_open(struct inode *inode, struct file *file)
534
{
535
int chain;
536
int unit = iminor(inode);
537
struct sound_unit *s;
538
const struct file_operations *new_fops = NULL;
539
540
chain=unit&0x0F;
541
if(chain==4 || chain==5) /* dsp/audio/dsp16 */
542
{
543
unit&=0xF0;
544
unit|=3;
545
chain=3;
546
}
547
548
spin_lock(&sound_loader_lock);
549
s = __look_for_unit(chain, unit);
550
if (s)
551
new_fops = fops_get(s->unit_fops);
552
if (preclaim_oss && !new_fops) {
553
spin_unlock(&sound_loader_lock);
554
555
/*
556
* Please, don't change this order or code.
557
* For ALSA slot means soundcard and OSS emulation code
558
* comes as add-on modules which aren't depend on
559
* ALSA toplevel modules for soundcards, thus we need
560
* load them at first. [Jaroslav Kysela <[email protected]>]
561
*/
562
request_module("sound-slot-%i", unit>>4);
563
request_module("sound-service-%i-%i", unit>>4, chain);
564
565
/*
566
* sound-slot/service-* module aliases are scheduled
567
* for removal in favor of the standard char-major-*
568
* module aliases. For the time being, generate both
569
* the legacy and standard module aliases to ease
570
* transition.
571
*/
572
if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
573
request_module("char-major-%d", SOUND_MAJOR);
574
575
spin_lock(&sound_loader_lock);
576
s = __look_for_unit(chain, unit);
577
if (s)
578
new_fops = fops_get(s->unit_fops);
579
}
580
spin_unlock(&sound_loader_lock);
581
582
if (!new_fops)
583
return -ENODEV;
584
585
/*
586
* We rely upon the fact that we can't be unloaded while the
587
* subdriver is there.
588
*/
589
replace_fops(file, new_fops);
590
591
if (!file->f_op->open)
592
return -ENODEV;
593
594
return file->f_op->open(inode, file);
595
}
596
597
MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
598
599
static void cleanup_oss_soundcore(void)
600
{
601
/* We have nothing to really do here - we know the lists must be
602
empty */
603
unregister_chrdev(SOUND_MAJOR, "sound");
604
}
605
606
static int __init init_oss_soundcore(void)
607
{
608
if (preclaim_oss &&
609
register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) < 0) {
610
printk(KERN_ERR "soundcore: sound device already in use.\n");
611
return -EBUSY;
612
}
613
614
return 0;
615
}
616
617
#endif /* CONFIG_SOUND_OSS_CORE */
618
619