cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sound_core.c (14557B)


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