aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-09-10 09:33:04 -0400
committerTakashi Iwai <tiwai@suse.de>2009-09-10 09:33:04 -0400
commit3827119e207823ff0f3e85271bef7a0dc953ee38 (patch)
tree66d2a24524628b3123b39e1364281886d2f9074f
parent9d416811f8cab11bf595b2880c557c33e3ae1ae9 (diff)
parent93fe4483e6fd3e71d17cd919de14b3b1f9eb3795 (diff)
Merge branch 'topic/soundcore-preclaim' into for-linus
* topic/soundcore-preclaim: sound: make OSS device number claiming optional and schedule its removal sound: request char-major-* module aliases for missing OSS devices chrdev: implement __[un]register_chrdev()
-rw-r--r--Documentation/feature-removal-schedule.txt24
-rw-r--r--fs/char_dev.c39
-rw-r--r--include/linux/fs.h19
-rw-r--r--sound/Kconfig28
-rw-r--r--sound/sound_core.c100
5 files changed, 176 insertions, 34 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 09e031c55887..f0690bbbd73c 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -468,3 +468,27 @@ Why: cpu_policy_rwsem has a new cleaner definition making it local to
468 cpufreq core and contained inside cpufreq.c. Other dependent 468 cpufreq core and contained inside cpufreq.c. Other dependent
469 drivers should not use it in order to safely avoid lockdep issues. 469 drivers should not use it in order to safely avoid lockdep issues.
470Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 470Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
471
472----------------------------
473
474What: sound-slot/service-* module aliases and related clutters in
475 sound/sound_core.c
476When: August 2010
477Why: OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR
478 (14) and requests modules using custom sound-slot/service-*
479 module aliases. The only benefit of doing this is allowing
480 use of custom module aliases which might as well be considered
481 a bug at this point. This preemptive claiming prevents
482 alternative OSS implementations.
483
484 Till the feature is removed, the kernel will be requesting
485 both sound-slot/service-* and the standard char-major-* module
486 aliases and allow turning off the pre-claiming selectively via
487 CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss
488 kernel parameter.
489
490 After the transition phase is complete, both the custom module
491 aliases and switches to disable it will go away. This removal
492 will also allow making ALSA OSS emulation independent of
493 sound_core. The dependency will be broken then too.
494Who: Tejun Heo <tj@kernel.org>
diff --git a/fs/char_dev.c b/fs/char_dev.c
index a173551e19d7..2f18c1e4e301 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -237,8 +237,10 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
237} 237}
238 238
239/** 239/**
240 * register_chrdev() - Register a major number for character devices. 240 * __register_chrdev() - create and register a cdev occupying a range of minors
241 * @major: major device number or 0 for dynamic allocation 241 * @major: major device number or 0 for dynamic allocation
242 * @baseminor: first of the requested range of minor numbers
243 * @count: the number of minor numbers required
242 * @name: name of this range of devices 244 * @name: name of this range of devices
243 * @fops: file operations associated with this devices 245 * @fops: file operations associated with this devices
244 * 246 *
@@ -254,19 +256,17 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
254 * /dev. It only helps to keep track of the different owners of devices. If 256 * /dev. It only helps to keep track of the different owners of devices. If
255 * your module name has only one type of devices it's ok to use e.g. the name 257 * your module name has only one type of devices it's ok to use e.g. the name
256 * of the module here. 258 * of the module here.
257 *
258 * This function registers a range of 256 minor numbers. The first minor number
259 * is 0.
260 */ 259 */
261int register_chrdev(unsigned int major, const char *name, 260int __register_chrdev(unsigned int major, unsigned int baseminor,
262 const struct file_operations *fops) 261 unsigned int count, const char *name,
262 const struct file_operations *fops)
263{ 263{
264 struct char_device_struct *cd; 264 struct char_device_struct *cd;
265 struct cdev *cdev; 265 struct cdev *cdev;
266 char *s; 266 char *s;
267 int err = -ENOMEM; 267 int err = -ENOMEM;
268 268
269 cd = __register_chrdev_region(major, 0, 256, name); 269 cd = __register_chrdev_region(major, baseminor, count, name);
270 if (IS_ERR(cd)) 270 if (IS_ERR(cd))
271 return PTR_ERR(cd); 271 return PTR_ERR(cd);
272 272
@@ -280,7 +280,7 @@ int register_chrdev(unsigned int major, const char *name,
280 for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) 280 for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
281 *s = '!'; 281 *s = '!';
282 282
283 err = cdev_add(cdev, MKDEV(cd->major, 0), 256); 283 err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
284 if (err) 284 if (err)
285 goto out; 285 goto out;
286 286
@@ -290,7 +290,7 @@ int register_chrdev(unsigned int major, const char *name,
290out: 290out:
291 kobject_put(&cdev->kobj); 291 kobject_put(&cdev->kobj);
292out2: 292out2:
293 kfree(__unregister_chrdev_region(cd->major, 0, 256)); 293 kfree(__unregister_chrdev_region(cd->major, baseminor, count));
294 return err; 294 return err;
295} 295}
296 296
@@ -316,10 +316,23 @@ void unregister_chrdev_region(dev_t from, unsigned count)
316 } 316 }
317} 317}
318 318
319void unregister_chrdev(unsigned int major, const char *name) 319/**
320 * __unregister_chrdev - unregister and destroy a cdev
321 * @major: major device number
322 * @baseminor: first of the range of minor numbers
323 * @count: the number of minor numbers this cdev is occupying
324 * @name: name of this range of devices
325 *
326 * Unregister and destroy the cdev occupying the region described by
327 * @major, @baseminor and @count. This function undoes what
328 * __register_chrdev() did.
329 */
330void __unregister_chrdev(unsigned int major, unsigned int baseminor,
331 unsigned int count, const char *name)
320{ 332{
321 struct char_device_struct *cd; 333 struct char_device_struct *cd;
322 cd = __unregister_chrdev_region(major, 0, 256); 334
335 cd = __unregister_chrdev_region(major, baseminor, count);
323 if (cd && cd->cdev) 336 if (cd && cd->cdev)
324 cdev_del(cd->cdev); 337 cdev_del(cd->cdev);
325 kfree(cd); 338 kfree(cd);
@@ -568,6 +581,6 @@ EXPORT_SYMBOL(cdev_alloc);
568EXPORT_SYMBOL(cdev_del); 581EXPORT_SYMBOL(cdev_del);
569EXPORT_SYMBOL(cdev_add); 582EXPORT_SYMBOL(cdev_add);
570EXPORT_SYMBOL(cdev_index); 583EXPORT_SYMBOL(cdev_index);
571EXPORT_SYMBOL(register_chrdev); 584EXPORT_SYMBOL(__register_chrdev);
572EXPORT_SYMBOL(unregister_chrdev); 585EXPORT_SYMBOL(__unregister_chrdev);
573EXPORT_SYMBOL(directly_mappable_cdev_bdi); 586EXPORT_SYMBOL(directly_mappable_cdev_bdi);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 73e9b643e455..3972ffb597c5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1998,12 +1998,25 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *);
1998#define CHRDEV_MAJOR_HASH_SIZE 255 1998#define CHRDEV_MAJOR_HASH_SIZE 255
1999extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); 1999extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
2000extern int register_chrdev_region(dev_t, unsigned, const char *); 2000extern int register_chrdev_region(dev_t, unsigned, const char *);
2001extern int register_chrdev(unsigned int, const char *, 2001extern int __register_chrdev(unsigned int major, unsigned int baseminor,
2002 const struct file_operations *); 2002 unsigned int count, const char *name,
2003extern void unregister_chrdev(unsigned int, const char *); 2003 const struct file_operations *fops);
2004extern void __unregister_chrdev(unsigned int major, unsigned int baseminor,
2005 unsigned int count, const char *name);
2004extern void unregister_chrdev_region(dev_t, unsigned); 2006extern void unregister_chrdev_region(dev_t, unsigned);
2005extern void chrdev_show(struct seq_file *,off_t); 2007extern void chrdev_show(struct seq_file *,off_t);
2006 2008
2009static inline int register_chrdev(unsigned int major, const char *name,
2010 const struct file_operations *fops)
2011{
2012 return __register_chrdev(major, 0, 256, name, fops);
2013}
2014
2015static inline void unregister_chrdev(unsigned int major, const char *name)
2016{
2017 __unregister_chrdev(major, 0, 256, name);
2018}
2019
2007/* fs/block_dev.c */ 2020/* fs/block_dev.c */
2008#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ 2021#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */
2009#define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */ 2022#define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */
diff --git a/sound/Kconfig b/sound/Kconfig
index 1eceb85287c5..439e15c8faa3 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -32,6 +32,34 @@ config SOUND_OSS_CORE
32 bool 32 bool
33 default n 33 default n
34 34
35config SOUND_OSS_CORE_PRECLAIM
36 bool "Preclaim OSS device numbers"
37 depends on SOUND_OSS_CORE
38 default y
39 help
40 With this option enabled, the kernel will claim all OSS device
41 numbers if any OSS support (native or emulation) is enabled
42 whether the respective module is loaded or not and try to load the
43 appropriate module using sound-slot/service-* and char-major-*
44 module aliases when one of the device numbers is opened. With
45 this option disabled, kernel will only claim actually in-use
46 device numbers and opening a missing device will generate only the
47 standard char-major-* aliases.
48
49 The only visible difference is use of additional module aliases
50 and whether OSS sound devices appear multiple times in
51 /proc/devices. sound-slot/service-* module aliases are scheduled
52 to be removed (ie. PRECLAIM won't be available) and this option is
53 to make the transition easier. This option can be overridden
54 during boot using the kernel parameter soundcore.preclaim_oss.
55
56 Disabling this allows alternative OSS implementations.
57
58 Please read Documentation/feature-removal-schedule.txt for
59 details.
60
61 If unusre, say Y.
62
35source "sound/oss/dmasound/Kconfig" 63source "sound/oss/dmasound/Kconfig"
36 64
37if !M68K 65if !M68K
diff --git a/sound/sound_core.c b/sound/sound_core.c
index a41f8b127f49..bb4b88e606bb 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -128,6 +128,46 @@ extern int msnd_pinnacle_init(void);
128#endif 128#endif
129 129
130/* 130/*
131 * By default, OSS sound_core claims full legacy minor range (0-255)
132 * of SOUND_MAJOR to trap open attempts to any sound minor and
133 * requests modules using custom sound-slot/service-* module aliases.
134 * The only benefit of doing this is allowing use of custom module
135 * aliases instead of the standard char-major-* ones. This behavior
136 * prevents alternative OSS implementation and is scheduled to be
137 * removed.
138 *
139 * CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel
140 * parameter are added to allow distros and developers to try and
141 * switch to alternative implementations without needing to rebuild
142 * the kernel in the meantime. If preclaim_oss is non-zero, the
143 * kernel will behave the same as before. All SOUND_MAJOR minors are
144 * preclaimed and the custom module aliases along with standard chrdev
145 * ones are emitted if a missing device is opened. If preclaim_oss is
146 * zero, sound_core only grabs what's actually in use and for missing
147 * devices only the standard chrdev aliases are requested.
148 *
149 * All these clutters are scheduled to be removed along with
150 * sound-slot/service-* module aliases. Please take a look at
151 * feature-removal-schedule.txt for details.
152 */
153#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
154static int preclaim_oss = 1;
155#else
156static int preclaim_oss = 0;
157#endif
158
159module_param(preclaim_oss, int, 0444);
160
161static int soundcore_open(struct inode *, struct file *);
162
163static const struct file_operations soundcore_fops =
164{
165 /* We must have an owner or the module locking fails */
166 .owner = THIS_MODULE,
167 .open = soundcore_open,
168};
169
170/*
131 * Low level list operator. Scan the ordered list, find a hole and 171 * Low level list operator. Scan the ordered list, find a hole and
132 * join into it. Called with the lock asserted 172 * join into it. Called with the lock asserted
133 */ 173 */
@@ -219,8 +259,9 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
219 259
220 if (!s) 260 if (!s)
221 return -ENOMEM; 261 return -ENOMEM;
222 262
223 spin_lock(&sound_loader_lock); 263 spin_lock(&sound_loader_lock);
264retry:
224 r = __sound_insert_unit(s, list, fops, index, low, top); 265 r = __sound_insert_unit(s, list, fops, index, low, top);
225 spin_unlock(&sound_loader_lock); 266 spin_unlock(&sound_loader_lock);
226 267
@@ -231,11 +272,31 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
231 else 272 else
232 sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP); 273 sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
233 274
275 if (!preclaim_oss) {
276 /*
277 * Something else might have grabbed the minor. If
278 * first free slot is requested, rescan with @low set
279 * to the next unit; otherwise, -EBUSY.
280 */
281 r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
282 &soundcore_fops);
283 if (r < 0) {
284 spin_lock(&sound_loader_lock);
285 __sound_remove_unit(list, s->unit_minor);
286 if (index < 0) {
287 low = s->unit_minor + SOUND_STEP;
288 goto retry;
289 }
290 spin_unlock(&sound_loader_lock);
291 return -EBUSY;
292 }
293 }
294
234 device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor), 295 device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
235 NULL, s->name+6); 296 NULL, s->name+6);
236 return r; 297 return s->unit_minor;
237 298
238 fail: 299fail:
239 kfree(s); 300 kfree(s);
240 return r; 301 return r;
241} 302}
@@ -254,6 +315,9 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
254 p = __sound_remove_unit(list, unit); 315 p = __sound_remove_unit(list, unit);
255 spin_unlock(&sound_loader_lock); 316 spin_unlock(&sound_loader_lock);
256 if (p) { 317 if (p) {
318 if (!preclaim_oss)
319 __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
320 p->name);
257 device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor)); 321 device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
258 kfree(p); 322 kfree(p);
259 } 323 }
@@ -491,19 +555,6 @@ void unregister_sound_dsp(int unit)
491 555
492EXPORT_SYMBOL(unregister_sound_dsp); 556EXPORT_SYMBOL(unregister_sound_dsp);
493 557
494/*
495 * Now our file operations
496 */
497
498static int soundcore_open(struct inode *, struct file *);
499
500static const struct file_operations soundcore_fops=
501{
502 /* We must have an owner or the module locking fails */
503 .owner = THIS_MODULE,
504 .open = soundcore_open,
505};
506
507static struct sound_unit *__look_for_unit(int chain, int unit) 558static struct sound_unit *__look_for_unit(int chain, int unit)
508{ 559{
509 struct sound_unit *s; 560 struct sound_unit *s;
@@ -539,8 +590,9 @@ static int soundcore_open(struct inode *inode, struct file *file)
539 s = __look_for_unit(chain, unit); 590 s = __look_for_unit(chain, unit);
540 if (s) 591 if (s)
541 new_fops = fops_get(s->unit_fops); 592 new_fops = fops_get(s->unit_fops);
542 if (!new_fops) { 593 if (preclaim_oss && !new_fops) {
543 spin_unlock(&sound_loader_lock); 594 spin_unlock(&sound_loader_lock);
595
544 /* 596 /*
545 * Please, don't change this order or code. 597 * Please, don't change this order or code.
546 * For ALSA slot means soundcard and OSS emulation code 598 * For ALSA slot means soundcard and OSS emulation code
@@ -550,6 +602,17 @@ static int soundcore_open(struct inode *inode, struct file *file)
550 */ 602 */
551 request_module("sound-slot-%i", unit>>4); 603 request_module("sound-slot-%i", unit>>4);
552 request_module("sound-service-%i-%i", unit>>4, chain); 604 request_module("sound-service-%i-%i", unit>>4, chain);
605
606 /*
607 * sound-slot/service-* module aliases are scheduled
608 * for removal in favor of the standard char-major-*
609 * module aliases. For the time being, generate both
610 * the legacy and standard module aliases to ease
611 * transition.
612 */
613 if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
614 request_module("char-major-%d", SOUND_MAJOR);
615
553 spin_lock(&sound_loader_lock); 616 spin_lock(&sound_loader_lock);
554 s = __look_for_unit(chain, unit); 617 s = __look_for_unit(chain, unit);
555 if (s) 618 if (s)
@@ -593,7 +656,8 @@ static void cleanup_oss_soundcore(void)
593 656
594static int __init init_oss_soundcore(void) 657static int __init init_oss_soundcore(void)
595{ 658{
596 if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) { 659 if (preclaim_oss &&
660 register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
597 printk(KERN_ERR "soundcore: sound device already in use.\n"); 661 printk(KERN_ERR "soundcore: sound device already in use.\n");
598 return -EBUSY; 662 return -EBUSY;
599 } 663 }