]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'topic/soundcore-preclaim' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:04 +0000 (15:33 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:04 +0000 (15:33 +0200)
* 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()

Documentation/feature-removal-schedule.txt
fs/char_dev.c
include/linux/fs.h
sound/Kconfig
sound/sound_core.c

index 09e031c558875139c72874b1ab78f322ed34d25f..f0690bbbd73c3ddc647a383dd678dbd444de2b2d 100644 (file)
@@ -468,3 +468,27 @@ Why:       cpu_policy_rwsem has a new cleaner definition making it local to
        cpufreq core and contained inside cpufreq.c. Other dependent
        drivers should not use it in order to safely avoid lockdep issues.
 Who:   Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+----------------------------
+
+What:  sound-slot/service-* module aliases and related clutters in
+       sound/sound_core.c
+When:  August 2010
+Why:   OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR
+       (14) and requests modules using custom sound-slot/service-*
+       module aliases.  The only benefit of doing this is allowing
+       use of custom module aliases which might as well be considered
+       a bug at this point.  This preemptive claiming prevents
+       alternative OSS implementations.
+
+       Till the feature is removed, the kernel will be requesting
+       both sound-slot/service-* and the standard char-major-* module
+       aliases and allow turning off the pre-claiming selectively via
+       CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss
+       kernel parameter.
+
+       After the transition phase is complete, both the custom module
+       aliases and switches to disable it will go away.  This removal
+       will also allow making ALSA OSS emulation independent of
+       sound_core.  The dependency will be broken then too.
+Who:   Tejun Heo <tj@kernel.org>
index a173551e19d79da5ae6132be9eaa24522abd4580..2f18c1e4e3013ccb059713cda2de1eacb2459a35 100644 (file)
@@ -237,8 +237,10 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
 }
 
 /**
- * register_chrdev() - Register a major number for character devices.
+ * __register_chrdev() - create and register a cdev occupying a range of minors
  * @major: major device number or 0 for dynamic allocation
+ * @baseminor: first of the requested range of minor numbers
+ * @count: the number of minor numbers required
  * @name: name of this range of devices
  * @fops: file operations associated with this devices
  *
@@ -254,19 +256,17 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
  * /dev. It only helps to keep track of the different owners of devices. If
  * your module name has only one type of devices it's ok to use e.g. the name
  * of the module here.
- *
- * This function registers a range of 256 minor numbers. The first minor number
- * is 0.
  */
-int register_chrdev(unsigned int major, const char *name,
-                   const struct file_operations *fops)
+int __register_chrdev(unsigned int major, unsigned int baseminor,
+                     unsigned int count, const char *name,
+                     const struct file_operations *fops)
 {
        struct char_device_struct *cd;
        struct cdev *cdev;
        char *s;
        int err = -ENOMEM;
 
-       cd = __register_chrdev_region(major, 0, 256, name);
+       cd = __register_chrdev_region(major, baseminor, count, name);
        if (IS_ERR(cd))
                return PTR_ERR(cd);
        
@@ -280,7 +280,7 @@ int register_chrdev(unsigned int major, const char *name,
        for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
                *s = '!';
                
-       err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
+       err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
        if (err)
                goto out;
 
@@ -290,7 +290,7 @@ int register_chrdev(unsigned int major, const char *name,
 out:
        kobject_put(&cdev->kobj);
 out2:
-       kfree(__unregister_chrdev_region(cd->major, 0, 256));
+       kfree(__unregister_chrdev_region(cd->major, baseminor, count));
        return err;
 }
 
@@ -316,10 +316,23 @@ void unregister_chrdev_region(dev_t from, unsigned count)
        }
 }
 
-void unregister_chrdev(unsigned int major, const char *name)
+/**
+ * __unregister_chrdev - unregister and destroy a cdev
+ * @major: major device number
+ * @baseminor: first of the range of minor numbers
+ * @count: the number of minor numbers this cdev is occupying
+ * @name: name of this range of devices
+ *
+ * Unregister and destroy the cdev occupying the region described by
+ * @major, @baseminor and @count.  This function undoes what
+ * __register_chrdev() did.
+ */
+void __unregister_chrdev(unsigned int major, unsigned int baseminor,
+                        unsigned int count, const char *name)
 {
        struct char_device_struct *cd;
-       cd = __unregister_chrdev_region(major, 0, 256);
+
+       cd = __unregister_chrdev_region(major, baseminor, count);
        if (cd && cd->cdev)
                cdev_del(cd->cdev);
        kfree(cd);
@@ -568,6 +581,6 @@ EXPORT_SYMBOL(cdev_alloc);
 EXPORT_SYMBOL(cdev_del);
 EXPORT_SYMBOL(cdev_add);
 EXPORT_SYMBOL(cdev_index);
-EXPORT_SYMBOL(register_chrdev);
-EXPORT_SYMBOL(unregister_chrdev);
+EXPORT_SYMBOL(__register_chrdev);
+EXPORT_SYMBOL(__unregister_chrdev);
 EXPORT_SYMBOL(directly_mappable_cdev_bdi);
index 73e9b643e45503dc6f01e31af2a8ec1f77de1264..3972ffb597c58c1a41bf9483c231593bd43783e5 100644 (file)
@@ -1998,12 +1998,25 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *);
 #define CHRDEV_MAJOR_HASH_SIZE 255
 extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
 extern int register_chrdev_region(dev_t, unsigned, const char *);
-extern int register_chrdev(unsigned int, const char *,
-                          const struct file_operations *);
-extern void unregister_chrdev(unsigned int, const char *);
+extern int __register_chrdev(unsigned int major, unsigned int baseminor,
+                            unsigned int count, const char *name,
+                            const struct file_operations *fops);
+extern void __unregister_chrdev(unsigned int major, unsigned int baseminor,
+                               unsigned int count, const char *name);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern void chrdev_show(struct seq_file *,off_t);
 
+static inline int register_chrdev(unsigned int major, const char *name,
+                                 const struct file_operations *fops)
+{
+       return __register_chrdev(major, 0, 256, name, fops);
+}
+
+static inline void unregister_chrdev(unsigned int major, const char *name)
+{
+       __unregister_chrdev(major, 0, 256, name);
+}
+
 /* fs/block_dev.c */
 #define BDEVNAME_SIZE  32      /* Largest string for a blockdev identifier */
 #define BDEVT_SIZE     10      /* Largest string for MAJ:MIN for blkdev */
index 1eceb85287c5f8197a25fe4a326c25b5dbf8e5be..439e15c8faa3d5f3ee7ef3b101bd9933c6ac6140 100644 (file)
@@ -32,6 +32,34 @@ config SOUND_OSS_CORE
        bool
        default n
 
+config SOUND_OSS_CORE_PRECLAIM
+       bool "Preclaim OSS device numbers"
+       depends on SOUND_OSS_CORE
+       default y
+       help
+         With this option enabled, the kernel will claim all OSS device
+         numbers if any OSS support (native or emulation) is enabled
+         whether the respective module is loaded or not and try to load the
+         appropriate module using sound-slot/service-* and char-major-*
+         module aliases when one of the device numbers is opened.  With
+         this option disabled, kernel will only claim actually in-use
+         device numbers and opening a missing device will generate only the
+         standard char-major-* aliases.
+
+         The only visible difference is use of additional module aliases
+         and whether OSS sound devices appear multiple times in
+         /proc/devices.  sound-slot/service-* module aliases are scheduled
+         to be removed (ie. PRECLAIM won't be available) and this option is
+         to make the transition easier.  This option can be overridden
+         during boot using the kernel parameter soundcore.preclaim_oss.
+
+         Disabling this allows alternative OSS implementations.
+
+         Please read Documentation/feature-removal-schedule.txt for
+         details.
+
+         If unusre, say Y.
+
 source "sound/oss/dmasound/Kconfig"
 
 if !M68K
index a41f8b127f49cceb1432183c4943482d6f61997f..bb4b88e606bba6a533ef8647da54bf666e62be64 100644 (file)
@@ -127,6 +127,46 @@ extern int msnd_classic_init(void);
 extern int msnd_pinnacle_init(void);
 #endif
 
+/*
+ * 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
+ * sound-slot/service-* module aliases.  Please take a look at
+ * feature-removal-schedule.txt for details.
+ */
+#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,
+};
+
 /*
  *     Low level list operator. Scan the ordered list, find a hole and
  *     join into it. Called with the lock asserted
@@ -219,8 +259,9 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
 
        if (!s)
                return -ENOMEM;
-               
+
        spin_lock(&sound_loader_lock);
+retry:
        r = __sound_insert_unit(s, list, fops, index, low, top);
        spin_unlock(&sound_loader_lock);
        
@@ -231,11 +272,31 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
        else
                sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
 
+       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);
+                       return -EBUSY;
+               }
+       }
+
        device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
                      NULL, s->name+6);
-       return r;
+       return s->unit_minor;
 
- fail:
+fail:
        kfree(s);
        return r;
 }
@@ -254,6 +315,9 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
        p = __sound_remove_unit(list, unit);
        spin_unlock(&sound_loader_lock);
        if (p) {
+               if (!preclaim_oss)
+                       __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
+                                           p->name);
                device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
                kfree(p);
        }
@@ -491,19 +555,6 @@ void unregister_sound_dsp(int unit)
 
 EXPORT_SYMBOL(unregister_sound_dsp);
 
-/*
- *     Now our file operations
- */
-
-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,
-};
-
 static struct sound_unit *__look_for_unit(int chain, int unit)
 {
        struct sound_unit *s;
@@ -539,8 +590,9 @@ static int soundcore_open(struct inode *inode, struct file *file)
        s = __look_for_unit(chain, unit);
        if (s)
                new_fops = fops_get(s->unit_fops);
-       if (!new_fops) {
+       if (preclaim_oss && !new_fops) {
                spin_unlock(&sound_loader_lock);
+
                /*
                 *  Please, don't change this order or code.
                 *  For ALSA slot means soundcard and OSS emulation code
@@ -550,6 +602,17 @@ static int soundcore_open(struct inode *inode, struct file *file)
                 */
                request_module("sound-slot-%i", unit>>4);
                request_module("sound-service-%i-%i", unit>>4, chain);
+
+               /*
+                * 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);
+
                spin_lock(&sound_loader_lock);
                s = __look_for_unit(chain, unit);
                if (s)
@@ -593,7 +656,8 @@ static void cleanup_oss_soundcore(void)
 
 static int __init init_oss_soundcore(void)
 {
-       if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {
+       if (preclaim_oss &&
+           register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
                printk(KERN_ERR "soundcore: sound device already in use.\n");
                return -EBUSY;
        }