Blame view

sound/sound_core.c 14.3 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
d886e87cb   Tejun Heo   sound: make OSS s...
3
4
5
6
7
8
9
10
11
12
13
   *	Sound core.  This file is composed of two parts.  sound_class
   *	which is common to both OSS and ALSA and OSS sound core which
   *	is used OSS or emulation of it.
   */
  
  /*
   * First, the common part.
   */
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/err.h>
954a973ca   Kay Sievers   sound: do not set...
14
15
  #include <linux/kdev_t.h>
  #include <linux/major.h>
3d1ee379b   Mark Brown   ALSA: Fix declara...
16
  #include <sound/core.h>
d886e87cb   Tejun Heo   sound: make OSS s...
17
18
19
  
  #ifdef CONFIG_SOUND_OSS_CORE
  static int __init init_oss_soundcore(void);
de30d36be   Krzysztof Helt   ALSA: fix section...
20
  static void cleanup_oss_soundcore(void);
d886e87cb   Tejun Heo   sound: make OSS s...
21
22
23
24
25
26
27
28
29
30
31
  #else
  static inline int init_oss_soundcore(void)	{ return 0; }
  static inline void cleanup_oss_soundcore(void)	{ }
  #endif
  
  struct class *sound_class;
  EXPORT_SYMBOL(sound_class);
  
  MODULE_DESCRIPTION("Core sound module");
  MODULE_AUTHOR("Alan Cox");
  MODULE_LICENSE("GPL");
2c9ede55e   Al Viro   switch device_get...
32
  static char *sound_devnode(struct device *dev, umode_t *mode)
7a9d56f6a   Kay Sievers   Driver Core: soun...
33
  {
954a973ca   Kay Sievers   sound: do not set...
34
35
  	if (MAJOR(dev->devt) == SOUND_MAJOR)
  		return NULL;
7a9d56f6a   Kay Sievers   Driver Core: soun...
36
37
  	return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
  }
d886e87cb   Tejun Heo   sound: make OSS s...
38
39
40
41
42
43
44
45
46
47
48
49
50
  static int __init init_soundcore(void)
  {
  	int rc;
  
  	rc = init_oss_soundcore();
  	if (rc)
  		return rc;
  
  	sound_class = class_create(THIS_MODULE, "sound");
  	if (IS_ERR(sound_class)) {
  		cleanup_oss_soundcore();
  		return PTR_ERR(sound_class);
  	}
e454cea20   Kay Sievers   Driver-Core: exte...
51
  	sound_class->devnode = sound_devnode;
7a9d56f6a   Kay Sievers   Driver Core: soun...
52

d886e87cb   Tejun Heo   sound: make OSS s...
53
54
55
56
57
58
59
60
  	return 0;
  }
  
  static void __exit cleanup_soundcore(void)
  {
  	cleanup_oss_soundcore();
  	class_destroy(sound_class);
  }
c181a13a4   Thadeu Lima de Souza Cascardo   ALSA: use subsys_...
61
  subsys_initcall(init_soundcore);
d886e87cb   Tejun Heo   sound: make OSS s...
62
63
64
65
66
67
  module_exit(cleanup_soundcore);
  
  
  #ifdef CONFIG_SOUND_OSS_CORE
  /*
   *	OSS sound core handling. Breaks out sound functions to submodules
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
   *	
2f1e593d4   Alan Cox   sound: use a comm...
69
   *	Author:		Alan Cox <alan@lxorguk.ukuu.org.uk>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
   *
   *	Fixes:
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
   *                         --------------------
   * 
   *	Top level handler for the sound subsystem. Various devices can
   *	plug into this. The fact they don't all go via OSS doesn't mean 
   *	they don't have to implement the OSS API. There is a lot of logic
   *	to keeping much of the OSS weight out of the code in a compatibility
   *	module, but it's up to the driver to rember to load it...
   *
   *	The code provides a set of functions for registration of devices
   *	by type. This is done rather than providing a single call so that
   *	we can hide any future changes in the internals (eg when we go to
   *	32bit dev_t) from the modules and their interface.
   *
   *	Secondly we need to allocate the dsp, dsp16 and audio devices as
   *	one. Thus we misuse the chains a bit to simplify this.
   *
   *	Thirdly to make it more fun and for 2.3.x and above we do all
   *	of this using fine grained locking.
   *
   *	FIXME: we have to resolve modules and fine grained load/unload
   *	locking at some point in 2.3.x.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  #include <linux/sound.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  #include <linux/kmod.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  
  #define SOUND_STEP 16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  struct sound_unit
  {
  	int unit_minor;
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
106
  	const struct file_operations *unit_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
  	struct sound_unit *next;
  	char name[32];
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  /*
93fe4483e   Tejun Heo   sound: make OSS d...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
   * By default, OSS sound_core claims full legacy minor range (0-255)
   * of SOUND_MAJOR to trap open attempts to any sound minor and
   * requests modules using custom sound-slot/service-* module aliases.
   * The only benefit of doing this is allowing use of custom module
   * aliases instead of the standard char-major-* ones.  This behavior
   * prevents alternative OSS implementation and is scheduled to be
   * removed.
   *
   * CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel
   * parameter are added to allow distros and developers to try and
   * switch to alternative implementations without needing to rebuild
   * the kernel in the meantime.  If preclaim_oss is non-zero, the
   * kernel will behave the same as before.  All SOUND_MAJOR minors are
   * preclaimed and the custom module aliases along with standard chrdev
   * ones are emitted if a missing device is opened.  If preclaim_oss is
   * zero, sound_core only grabs what's actually in use and for missing
   * devices only the standard chrdev aliases are requested.
   *
   * All these clutters are scheduled to be removed along with
8f6e60419   Tao Ma   sound: remove ref...
130
   * sound-slot/service-* module aliases.
93fe4483e   Tejun Heo   sound: make OSS d...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
   */
  #ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
  static int preclaim_oss = 1;
  #else
  static int preclaim_oss = 0;
  #endif
  
  module_param(preclaim_oss, int, 0444);
  
  static int soundcore_open(struct inode *, struct file *);
  
  static const struct file_operations soundcore_fops =
  {
  	/* We must have an owner or the module locking fails */
  	.owner	= THIS_MODULE,
  	.open	= soundcore_open,
6038f373a   Arnd Bergmann   llseek: automatic...
147
  	.llseek = noop_llseek,
93fe4483e   Tejun Heo   sound: make OSS d...
148
149
150
  };
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
   *	Low level list operator. Scan the ordered list, find a hole and
   *	join into it. Called with the lock asserted
   */
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
154
  static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  {
  	int n=low;
  
  	if (index < 0) {	/* first free */
  
  		while (*list && (*list)->unit_minor<n)
  			list=&((*list)->next);
  
  		while(n<top)
  		{
  			/* Found a hole ? */
  			if(*list==NULL || (*list)->unit_minor>n)
  				break;
  			list=&((*list)->next);
  			n+=SOUND_STEP;
  		}
  
  		if(n>=top)
  			return -ENOENT;
  	} else {
  		n = low+(index*16);
  		while (*list) {
  			if ((*list)->unit_minor==n)
  				return -EBUSY;
  			if ((*list)->unit_minor>n)
  				break;
  			list=&((*list)->next);
  		}
  	}	
  		
  	/*
  	 *	Fill it in
  	 */
  	 
  	s->unit_minor=n;
  	s->unit_fops=fops;
  	
  	/*
  	 *	Link it
  	 */
  	 
  	s->next=*list;
  	*list=s;
  	
  	
  	return n;
  }
  
  /*
   *	Remove a node from the chain. Called with the lock asserted
   */
   
  static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
  {
  	while(*list)
  	{
  		struct sound_unit *p=*list;
  		if(p->unit_minor==unit)
  		{
  			*list=p->next;
  			return p;
  		}
  		list=&(p->next);
  	}
  	printk(KERN_ERR "Sound device %d went missing!
  ", unit);
  	return NULL;
  }
  
  /*
   *	This lock guards the sound loader list.
   */
  
  static DEFINE_SPINLOCK(sound_loader_lock);
  
  /*
   *	Allocate the controlling structure and add it to the sound driver
   *	list. Acquires locks as needed
   */
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
234
  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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
  {
  	struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
  	int r;
  
  	if (!s)
  		return -ENOMEM;
93fe4483e   Tejun Heo   sound: make OSS d...
241

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	spin_lock(&sound_loader_lock);
93fe4483e   Tejun Heo   sound: make OSS d...
243
  retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
  	r = __sound_insert_unit(s, list, fops, index, low, top);
  	spin_unlock(&sound_loader_lock);
  	
  	if (r < 0)
  		goto fail;
  	else if (r < SOUND_STEP)
  		sprintf(s->name, "sound/%s", name);
  	else
  		sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
93fe4483e   Tejun Heo   sound: make OSS d...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  	if (!preclaim_oss) {
  		/*
  		 * Something else might have grabbed the minor.  If
  		 * first free slot is requested, rescan with @low set
  		 * to the next unit; otherwise, -EBUSY.
  		 */
  		r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
  				      &soundcore_fops);
  		if (r < 0) {
  			spin_lock(&sound_loader_lock);
  			__sound_remove_unit(list, s->unit_minor);
  			if (index < 0) {
  				low = s->unit_minor + SOUND_STEP;
  				goto retry;
  			}
  			spin_unlock(&sound_loader_lock);
c7cd7c748   Wenwen Wang   sound: fix a memo...
269
270
  			r = -EBUSY;
  			goto fail;
93fe4483e   Tejun Heo   sound: make OSS d...
271
272
  		}
  	}
abe9ab8f6   Greg Kroah-Hartman   device create: so...
273
  	device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
02aa2a376   Kees Cook   drivers: avoid fo...
274
  		      NULL, "%s", s->name+6);
93fe4483e   Tejun Heo   sound: make OSS d...
275
  	return s->unit_minor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276

93fe4483e   Tejun Heo   sound: make OSS d...
277
  fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	kfree(s);
  	return r;
  }
  
  /*
   *	Remove a unit. Acquires locks as needed. The drivers MUST have
   *	completed the removal before their file operations become
   *	invalid.
   */
   	
  static void sound_remove_unit(struct sound_unit **list, int unit)
  {
  	struct sound_unit *p;
  
  	spin_lock(&sound_loader_lock);
  	p = __sound_remove_unit(list, unit);
  	spin_unlock(&sound_loader_lock);
  	if (p) {
93fe4483e   Tejun Heo   sound: make OSS d...
296
297
298
  		if (!preclaim_oss)
  			__unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
  					    p->name);
d80f19fab   Greg Kroah-Hartman   Driver core: conv...
299
  		device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  		kfree(p);
  	}
  }
  
  /*
   *	Allocations
   *
   *	0	*16		Mixers
   *	1	*8		Sequencers
   *	2	*16		Midi
   *	3	*16		DSP
   *	4	*16		SunDSP
   *	5	*16		DSP16
   *	6	--		sndstat (obsolete)
   *	7	*16		unused
   *	8	--		alternate sequencer (see above)
   *	9	*16		raw synthesizer access
   *	10	*16		unused
   *	11	*16		unused
   *	12	*16		unused
   *	13	*16		unused
   *	14	*16		unused
   *	15	*16		unused
   */
  
  static struct sound_unit *chains[SOUND_STEP];
  
  /**
d568121ce   Takashi Iwai   [PATCH] Assign de...
328
   *	register_sound_special_device - register a special sound node
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
   *	@fops: File operations for the driver
   *	@unit: Unit number to allocate
d568121ce   Takashi Iwai   [PATCH] Assign de...
331
   *      @dev: device pointer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
   *
   *	Allocate a special sound device by minor number from the sound
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
334
335
336
   *	subsystem.
   *
   *	Return: The allocated number is returned on success. On failure,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
   *	a negative error code is returned.
   */
   
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
340
  int register_sound_special_device(const struct file_operations *fops, int unit,
d568121ce   Takashi Iwai   [PATCH] Assign de...
341
  				  struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  {
  	const int chain = unit % SOUND_STEP;
2abb80176   Takashi Iwai   sound: allow the ...
344
  	int max_unit = 256;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  	const char *name;
  	char _name[16];
  
  	switch (chain) {
  	    case 0:
  		name = "mixer";
  		break;
  	    case 1:
  		name = "sequencer";
  		if (unit >= SOUND_STEP)
  			goto __unknown;
  		max_unit = unit + 1;
  		break;
  	    case 2:
  		name = "midi";
  		break;
  	    case 3:
  		name = "dsp";
  		break;
  	    case 4:
  		name = "audio";
  		break;
848669da3   Takashi Iwai   sound: Use sound_...
367
368
369
  	    case 5:
  		name = "dspW";
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  	    case 8:
  		name = "sequencer2";
  		if (unit >= SOUND_STEP)
  			goto __unknown;
  		max_unit = unit + 1;
  		break;
  	    case 9:
  		name = "dmmidi";
  		break;
  	    case 10:
  		name = "dmfm";
  		break;
  	    case 12:
  		name = "adsp";
  		break;
  	    case 13:
  		name = "amidi";
  		break;
  	    case 14:
  		name = "admmidi";
  		break;
  	    default:
  	    	{
  		    __unknown:
  			sprintf(_name, "unknown%d", chain);
  		    	if (unit >= SOUND_STEP)
  		    		strcat(_name, "-");
  		    	name = _name;
  		}
  		break;
  	}
  	return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
6a73cf46c   Joe Perches   sound: Use octal ...
402
  				 name, 0600, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  }
   
d568121ce   Takashi Iwai   [PATCH] Assign de...
405
  EXPORT_SYMBOL(register_sound_special_device);
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
406
  int register_sound_special(const struct file_operations *fops, int unit)
d568121ce   Takashi Iwai   [PATCH] Assign de...
407
408
409
  {
  	return register_sound_special_device(fops, unit, NULL);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
415
416
417
  EXPORT_SYMBOL(register_sound_special);
  
  /**
   *	register_sound_mixer - register a mixer device
   *	@fops: File operations for the driver
   *	@dev: Unit number to allocate
   *
   *	Allocate a mixer device. Unit is the number of the mixer requested.
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
418
419
420
421
   *	Pass -1 to request the next free mixer unit.
   *
   *	Return: On success, the allocated number is returned. On failure,
   *	a negative error code is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
   */
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
423
  int register_sound_mixer(const struct file_operations *fops, int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  {
  	return sound_insert_unit(&chains[0], fops, dev, 0, 128,
6a73cf46c   Joe Perches   sound: Use octal ...
426
  				 "mixer", 0600, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  }
  
  EXPORT_SYMBOL(register_sound_mixer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
440
  /*
   *	DSP's are registered as a triple. Register only one and cheat
   *	in open - see below.
   */
   
  /**
   *	register_sound_dsp - register a DSP device
   *	@fops: File operations for the driver
   *	@dev: Unit number to allocate
   *
   *	Allocate a DSP device. Unit is the number of the DSP requested.
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
441
   *	Pass -1 to request the next free DSP unit.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
   *
   *	This function allocates both the audio and dsp device entries together
   *	and will always allocate them as a matching pair - eg dsp3/audio3
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
445
446
447
   *
   *	Return: On success, the allocated number is returned. On failure,
   *	a negative error code is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
   */
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
449
  int register_sound_dsp(const struct file_operations *fops, int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
  {
  	return sound_insert_unit(&chains[3], fops, dev, 3, 131,
6a73cf46c   Joe Perches   sound: Use octal ...
452
  				 "dsp", 0600, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
  }
  
  EXPORT_SYMBOL(register_sound_dsp);
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
   *	unregister_sound_special - unregister a special sound device
   *	@unit: unit number to allocate
   *
   *	Release a sound device that was allocated with
   *	register_sound_special(). The unit passed is the return value from
   *	the register function.
   */
  
  
  void unregister_sound_special(int unit)
  {
  	sound_remove_unit(&chains[unit % SOUND_STEP], unit);
  }
   
  EXPORT_SYMBOL(unregister_sound_special);
  
  /**
   *	unregister_sound_mixer - unregister a mixer
   *	@unit: unit number to allocate
   *
   *	Release a sound device that was allocated with register_sound_mixer().
   *	The unit passed is the return value from the register function.
   */
  
  void unregister_sound_mixer(int unit)
  {
  	sound_remove_unit(&chains[0], unit);
  }
  
  EXPORT_SYMBOL(unregister_sound_mixer);
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
497
498
499
500
   *	unregister_sound_dsp - unregister a DSP device
   *	@unit: unit number to allocate
   *
   *	Release a sound device that was allocated with register_sound_dsp().
   *	The unit passed is the return value from the register function.
   *
   *	Both of the allocated units are released together automatically.
   */
  
  void unregister_sound_dsp(int unit)
  {
a39c4ad10   Hannes Eder   sound/sound_core:...
501
  	sound_remove_unit(&chains[3], unit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
504
505
  }
  
  
  EXPORT_SYMBOL(unregister_sound_dsp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
511
512
513
514
515
516
517
518
  static struct sound_unit *__look_for_unit(int chain, int unit)
  {
  	struct sound_unit *s;
  	
  	s=chains[chain];
  	while(s && s->unit_minor <= unit)
  	{
  		if(s->unit_minor==unit)
  			return s;
  		s=s->next;
  	}
  	return NULL;
  }
a39c4ad10   Hannes Eder   sound/sound_core:...
519
  static int soundcore_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
523
  {
  	int chain;
  	int unit = iminor(inode);
  	struct sound_unit *s;
99ac48f54   Arjan van de Ven   [PATCH] mark f_op...
524
  	const struct file_operations *new_fops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
530
531
532
533
534
535
536
537
  
  	chain=unit&0x0F;
  	if(chain==4 || chain==5)	/* dsp/audio/dsp16 */
  	{
  		unit&=0xF0;
  		unit|=3;
  		chain=3;
  	}
  	
  	spin_lock(&sound_loader_lock);
  	s = __look_for_unit(chain, unit);
  	if (s)
  		new_fops = fops_get(s->unit_fops);
93fe4483e   Tejun Heo   sound: make OSS d...
538
  	if (preclaim_oss && !new_fops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  		spin_unlock(&sound_loader_lock);
0a848680a   Tejun Heo   sound: request ch...
540

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
545
546
547
548
549
  		/*
  		 *  Please, don't change this order or code.
  		 *  For ALSA slot means soundcard and OSS emulation code
  		 *  comes as add-on modules which aren't depend on
  		 *  ALSA toplevel modules for soundcards, thus we need
  		 *  load them at first.	  [Jaroslav Kysela <perex@jcu.cz>]
  		 */
  		request_module("sound-slot-%i", unit>>4);
  		request_module("sound-service-%i-%i", unit>>4, chain);
0a848680a   Tejun Heo   sound: request ch...
550
551
552
553
554
555
556
557
558
559
  
  		/*
  		 * sound-slot/service-* module aliases are scheduled
  		 * for removal in favor of the standard char-major-*
  		 * module aliases.  For the time being, generate both
  		 * the legacy and standard module aliases to ease
  		 * transition.
  		 */
  		if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
  			request_module("char-major-%d", SOUND_MAJOR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
  		spin_lock(&sound_loader_lock);
  		s = __look_for_unit(chain, unit);
  		if (s)
  			new_fops = fops_get(s->unit_fops);
  	}
e84f9e57b   Al Viro   consolidate the r...
565
  	spin_unlock(&sound_loader_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
  	if (new_fops) {
  		/*
  		 * We rely upon the fact that we can't be unloaded while the
e84f9e57b   Al Viro   consolidate the r...
569
  		 * subdriver is there.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  		 */
  		int err = 0;
e84f9e57b   Al Viro   consolidate the r...
572
  		replace_fops(file, new_fops);
171d9f7d7   John Kacur   soundcore_open: R...
573

90dc763fe   Arnd Bergmann   sound: push BKL i...
574
  		if (file->f_op->open)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  			err = file->f_op->open(inode,file);
171d9f7d7   John Kacur   soundcore_open: R...
576

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  		return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
  	return -ENODEV;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
de30d36be   Krzysztof Helt   ALSA: fix section...
582
  static void cleanup_oss_soundcore(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
  {
  	/* We have nothing to really do here - we know the lists must be
  	   empty */
  	unregister_chrdev(SOUND_MAJOR, "sound");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  }
d886e87cb   Tejun Heo   sound: make OSS s...
588
  static int __init init_oss_soundcore(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  {
93fe4483e   Tejun Heo   sound: make OSS d...
590
  	if (preclaim_oss &&
cb68429d1   Alexey Khoroshilov   sound: fix check ...
591
  	    register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
  		printk(KERN_ERR "soundcore: sound device already in use.
  ");
  		return -EBUSY;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
  
  	return 0;
  }
d886e87cb   Tejun Heo   sound: make OSS s...
599
  #endif /* CONFIG_SOUND_OSS_CORE */