1
2
3#include <linux/config.h>
4#include <linux/module.h>
5#include <linux/init.h>
6#include <linux/slab.h>
7#include <linux/types.h>
8#include <linux/kernel.h>
9#include <linux/fs.h>
10#include <linux/sound.h>
11#include <linux/major.h>
12#include <linux/kmod.h>
13#include <linux/devfs_fs_kernel.h>
14
15#define SOUND_STEP 16
16
17
18struct sound_unit
19{
20	int unit_minor;
21	struct file_operations *unit_fops;
22	struct sound_unit *next;
23	devfs_handle_t de;
24};
25
26#ifdef CONFIG_SOUND_MSNDCLAS
27extern int msnd_classic_init(void);
28#endif
29#ifdef CONFIG_SOUND_MSNDPIN
30extern int msnd_pinnacle_init(void);
31#endif
32
33/*
34 *	Low level list operator. Scan the ordered list, find a hole and
35 *	join into it. Called with the lock asserted
36 */
37
38static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
39{
40	int n=low;
41
42	if (index < 0) {	/* first free */
43
44		while (*list && (*list)->unit_minor<n)
45			list=&((*list)->next);
46
47		while(n<top)
48		{
49			/* Found a hole ? */
50			if(*list==NULL || (*list)->unit_minor>n)
51				break;
52			list=&((*list)->next);
53			n+=SOUND_STEP;
54		}
55
56		if(n>=top)
57			return -ENOENT;
58	} else {
59		n = low+(index*16);
60		while (*list) {
61			if ((*list)->unit_minor==n)
62				return -EBUSY;
63			if ((*list)->unit_minor>n)
64				break;
65			list=&((*list)->next);
66		}
67	}
68
69	/*
70	 *	Fill it in
71	 */
72
73	s->unit_minor=n;
74	s->unit_fops=fops;
75
76	/*
77	 *	Link it
78	 */
79
80	s->next=*list;
81	*list=s;
82
83
84	MOD_INC_USE_COUNT;
85	return n;
86}
87
88/*
89 *	Remove a node from the chain. Called with the lock asserted
90 */
91
92static void __sound_remove_unit(struct sound_unit **list, int unit)
93{
94	while(*list)
95	{
96		struct sound_unit *p=*list;
97		if(p->unit_minor==unit)
98		{
99			*list=p->next;
100			devfs_unregister (p->de);
101			kfree(p);
102			MOD_DEC_USE_COUNT;
103			return;
104		}
105		list=&(p->next);
106	}
107	printk(KERN_ERR "Sound device %d went missing!\n", unit);
108}
109
110/*
111 *	This lock guards the sound loader list.
112 */
113
114static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
115
116/*
117 *	Allocate the controlling structure and add it to the sound driver
118 *	list. Acquires locks as needed
119 */
120
121static devfs_handle_t devfs_handle;
122
123static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
124{
125	int r;
126	struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL);
127	char name_buf[16];
128
129	if(s==NULL)
130		return -ENOMEM;
131
132	spin_lock(&sound_loader_lock);
133	r=__sound_insert_unit(s,list,fops,index,low,top);
134	spin_unlock(&sound_loader_lock);
135
136	if(r<0)
137	{
138		kfree(s);
139		return r;
140	}
141
142	if (r == low)
143		sprintf (name_buf, "%s", name);
144	else
145		sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP);
146	s->de = devfs_register (devfs_handle, name_buf,
147				DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor,
148				S_IFCHR | mode, fops, NULL);
149	return r;
150}
151
152/*
153 *	Remove a unit. Acquires locks as needed. The drivers MUST have
154 *	completed the removal before their file operations become
155 *	invalid.
156 */
157
158static void sound_remove_unit(struct sound_unit **list, int unit)
159{
160	spin_lock(&sound_loader_lock);
161	__sound_remove_unit(list, unit);
162	spin_unlock(&sound_loader_lock);
163}
164
165/*
166 *	Allocations
167 *
168 *	0	*16		Mixers
169 *	1	*8		Sequencers
170 *	2	*16		Midi
171 *	3	*16		DSP
172 *	4	*16		SunDSP
173 *	5	*16		DSP16
174 *	6	--		sndstat (obsolete)
175 *	7	*16		unused
176 *	8	--		alternate sequencer (see above)
177 *	9	*16		raw synthesizer access
178 *	10	*16		unused
179 *	11	*16		unused
180 *	12	*16		unused
181 *	13	*16		unused
182 *	14	*16		unused
183 *	15	*16		unused
184 */
185
186static struct sound_unit *chains[16];
187
188/**
189 *	register_sound_special - register a special sound node
190 *	@fops: File operations for the driver
191 *	@unit: Unit number to allocate
192 *
193 *	Allocate a special sound device by minor number from the sound
194 *	subsystem. The allocated number is returned on succes. On failure
195 *	a negative error code is returned.
196 */
197
198int register_sound_special(struct file_operations *fops, int unit)
199{
200	char *name;
201
202	switch (unit) {
203	    case 0:
204		name = "mixer";
205		break;
206	    case 1:
207		name = "sequencer";
208		break;
209	    case 2:
210		name = "midi00";
211		break;
212	    case 3:
213		name = "dsp";
214		break;
215	    case 4:
216		name = "audio";
217		break;
218	    case 5:
219		name = "unknown5";
220		break;
221	    case 6:		/* Was once sndstat */
222		name = "unknown6";
223		break;
224	    case 7:
225		name = "unknown7";
226		break;
227	    case 8:
228		name = "sequencer2";
229		break;
230	    case 9:
231		name = "dmmidi";
232		break;
233	    case 10:
234		name = "dmfm";
235		break;
236	    case 11:
237		name = "unknown11";
238		break;
239	    case 12:
240		name = "adsp";
241		break;
242	    case 13:
243		name = "amidi";
244		break;
245	    case 14:
246		name = "admmidi";
247		break;
248	    default:
249		name = "unknown";
250		break;
251	}
252	return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1,
253				 name, S_IRUSR | S_IWUSR);
254}
255
256EXPORT_SYMBOL(register_sound_special);
257
258/**
259 *	register_sound_mixer - register a mixer device
260 *	@fops: File operations for the driver
261 *	@dev: Unit number to allocate
262 *
263 *	Allocate a mixer device. Unit is the number of the mixer requested.
264 *	Pass -1 to request the next free mixer unit. On success the allocated
265 *	number is returned, on failure a negative error code is returned.
266 */
267
268int register_sound_mixer(struct file_operations *fops, int dev)
269{
270	return sound_insert_unit(&chains[0], fops, dev, 0, 128,
271				 "mixer", S_IRUSR | S_IWUSR);
272}
273
274EXPORT_SYMBOL(register_sound_mixer);
275
276/**
277 *	register_sound_midi - register a midi device
278 *	@fops: File operations for the driver
279 *	@dev: Unit number to allocate
280 *
281 *	Allocate a midi device. Unit is the number of the midi device requested.
282 *	Pass -1 to request the next free midi unit. On success the allocated
283 *	number is returned, on failure a negative error code is returned.
284 */
285
286int register_sound_midi(struct file_operations *fops, int dev)
287{
288	return sound_insert_unit(&chains[2], fops, dev, 2, 130,
289				 "midi", S_IRUSR | S_IWUSR);
290}
291
292EXPORT_SYMBOL(register_sound_midi);
293
294/*
295 *	DSP's are registered as a triple. Register only one and cheat
296 *	in open - see below.
297 */
298
299/**
300 *	register_sound_dsp - register a DSP device
301 *	@fops: File operations for the driver
302 *	@dev: Unit number to allocate
303 *
304 *	Allocate a DSP device. Unit is the number of the DSP requested.
305 *	Pass -1 to request the next free DSP unit. On success the allocated
306 *	number is returned, on failure a negative error code is returned.
307 *
308 *	This function allocates both the audio and dsp device entries together
309 *	and will always allocate them as a matching pair - eg dsp3/audio3
310 */
311
312int register_sound_dsp(struct file_operations *fops, int dev)
313{
314	return sound_insert_unit(&chains[3], fops, dev, 3, 131,
315				 "dsp", S_IWUSR | S_IRUSR);
316}
317
318EXPORT_SYMBOL(register_sound_dsp);
319
320/**
321 *	register_sound_synth - register a synth device
322 *	@fops: File operations for the driver
323 *	@dev: Unit number to allocate
324 *
325 *	Allocate a synth device. Unit is the number of the synth device requested.
326 *	Pass -1 to request the next free synth unit. On success the allocated
327 *	number is returned, on failure a negative error code is returned.
328 */
329
330
331int register_sound_synth(struct file_operations *fops, int dev)
332{
333	return sound_insert_unit(&chains[9], fops, dev, 9, 137,
334				 "synth", S_IRUSR | S_IWUSR);
335}
336
337EXPORT_SYMBOL(register_sound_synth);
338
339/**
340 *	unregister_sound_special - unregister a special sound device
341 *	@unit: unit number to allocate
342 *
343 *	Release a sound device that was allocated with
344 *	register_sound_special(). The unit passed is the return value from
345 *	the register function.
346 */
347
348
349void unregister_sound_special(int unit)
350{
351	sound_remove_unit(&chains[unit&15], unit);
352}
353
354EXPORT_SYMBOL(unregister_sound_special);
355
356/**
357 *	unregister_sound_mixer - unregister a mixer
358 *	@unit: unit number to allocate
359 *
360 *	Release a sound device that was allocated with register_sound_mixer().
361 *	The unit passed is the return value from the register function.
362 */
363
364void unregister_sound_mixer(int unit)
365{
366	sound_remove_unit(&chains[0], unit);
367}
368
369EXPORT_SYMBOL(unregister_sound_mixer);
370
371/**
372 *	unregister_sound_midi - unregister a midi device
373 *	@unit: unit number to allocate
374 *
375 *	Release a sound device that was allocated with register_sound_midi().
376 *	The unit passed is the return value from the register function.
377 */
378
379void unregister_sound_midi(int unit)
380{
381	return sound_remove_unit(&chains[2], unit);
382}
383
384EXPORT_SYMBOL(unregister_sound_midi);
385
386/**
387 *	unregister_sound_dsp - unregister a DSP device
388 *	@unit: unit number to allocate
389 *
390 *	Release a sound device that was allocated with register_sound_dsp().
391 *	The unit passed is the return value from the register function.
392 *
393 *	Both of the allocated units are released together automatically.
394 */
395
396void unregister_sound_dsp(int unit)
397{
398	return sound_remove_unit(&chains[3], unit);
399}
400
401
402EXPORT_SYMBOL(unregister_sound_dsp);
403
404/**
405 *	unregister_sound_synth - unregister a synth device
406 *	@unit: unit number to allocate
407 *
408 *	Release a sound device that was allocated with register_sound_synth().
409 *	The unit passed is the return value from the register function.
410 */
411
412void unregister_sound_synth(int unit)
413{
414	return sound_remove_unit(&chains[9], unit);
415}
416
417EXPORT_SYMBOL(unregister_sound_synth);
418
419/*
420 *	Now our file operations
421 */
422
423static int soundcore_open(struct inode *, struct file *);
424
425static struct file_operations soundcore_fops=
426{
427	/* We must have an owner or the module locking fails */
428	owner:	THIS_MODULE,
429	open:	soundcore_open,
430};
431
432static struct sound_unit *__look_for_unit(int chain, int unit)
433{
434	struct sound_unit *s;
435
436	s=chains[chain];
437	while(s && s->unit_minor <= unit)
438	{
439		if(s->unit_minor==unit)
440			return s;
441		s=s->next;
442	}
443	return NULL;
444}
445
446int soundcore_open(struct inode *inode, struct file *file)
447{
448	int chain;
449	int unit=MINOR(inode->i_rdev);
450	struct sound_unit *s;
451	struct file_operations *new_fops = NULL;
452
453	chain=unit&0x0F;
454	if(chain==4 || chain==5)	/* dsp/audio/dsp16 */
455	{
456		unit&=0xF0;
457		unit|=3;
458		chain=3;
459	}
460
461	spin_lock(&sound_loader_lock);
462	s = __look_for_unit(chain, unit);
463	if (s)
464		new_fops = fops_get(s->unit_fops);
465	if (!new_fops) {
466		char mod[32];
467
468		spin_unlock(&sound_loader_lock);
469		/*
470		 *  Please, don't change this order or code.
471		 *  For ALSA slot means soundcard and OSS emulation code
472		 *  comes as add-on modules which aren't depend on
473		 *  ALSA toplevel modules for soundcards, thus we need
474		 *  load them at first.	  [Jaroslav Kysela <perex@jcu.cz>]
475		 */
476		sprintf(mod, "sound-slot-%i", unit>>4);
477		request_module(mod);
478		sprintf(mod, "sound-service-%i-%i", unit>>4, chain);
479		request_module(mod);
480		spin_lock(&sound_loader_lock);
481		s = __look_for_unit(chain, unit);
482		if (s)
483			new_fops = fops_get(s->unit_fops);
484	}
485	if (new_fops) {
486		/*
487		 * We rely upon the fact that we can't be unloaded while the
488		 * subdriver is there, so if ->open() is successful we can
489		 * safely drop the reference counter and if it is not we can
490		 * revert to old ->f_op. Ugly, indeed, but that's the cost of
491		 * switching ->f_op in the first place.
492		 */
493		int err = 0;
494		struct file_operations *old_fops = file->f_op;
495		file->f_op = new_fops;
496		spin_unlock(&sound_loader_lock);
497		if(file->f_op->open)
498			err = file->f_op->open(inode,file);
499		if (err) {
500			fops_put(file->f_op);
501			file->f_op = fops_get(old_fops);
502		}
503		fops_put(old_fops);
504		return err;
505	}
506	spin_unlock(&sound_loader_lock);
507	return -ENODEV;
508}
509
510extern int mod_firmware_load(const char *, char **);
511EXPORT_SYMBOL(mod_firmware_load);
512
513
514MODULE_DESCRIPTION("Core sound module");
515MODULE_AUTHOR("Alan Cox");
516MODULE_LICENSE("GPL");
517
518static void __exit cleanup_soundcore(void)
519{
520	/* We have nothing to really do here - we know the lists must be
521	   empty */
522	devfs_unregister_chrdev(SOUND_MAJOR, "sound");
523	devfs_unregister (devfs_handle);
524}
525
526static int __init init_soundcore(void)
527{
528	if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
529	{
530		printk(KERN_ERR "soundcore: sound device already in use.\n");
531		return -EBUSY;
532	}
533	devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
534
535	return 0;
536}
537
538module_init(init_soundcore);
539module_exit(cleanup_soundcore);
540