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