Merge branch 'akpm' (Andrew's patch-bomb)
[linux-2.6.git] / sound / sound_core.c
index 786067c..c6e81fb 100644 (file)
@@ -29,7 +29,7 @@ MODULE_DESCRIPTION("Core sound module");
 MODULE_AUTHOR("Alan Cox");
 MODULE_LICENSE("GPL");
 
-static char *sound_nodename(struct device *dev)
+static char *sound_devnode(struct device *dev, umode_t *mode)
 {
        if (MAJOR(dev->devt) == SOUND_MAJOR)
                return NULL;
@@ -50,7 +50,7 @@ static int __init init_soundcore(void)
                return PTR_ERR(sound_class);
        }
 
-       sound_class->nodename = sound_nodename;
+       sound_class->devnode = sound_devnode;
 
        return 0;
 }
@@ -61,7 +61,7 @@ static void __exit cleanup_soundcore(void)
        class_destroy(sound_class);
 }
 
-module_init(init_soundcore);
+subsys_initcall(init_soundcore);
 module_exit(cleanup_soundcore);
 
 
@@ -104,7 +104,6 @@ module_exit(cleanup_soundcore);
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sound.h>
@@ -128,6 +127,47 @@ 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,
+       .llseek = noop_llseek,
+};
+
+/*
  *     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);
        }
@@ -289,7 +353,7 @@ static struct sound_unit *chains[SOUND_STEP];
  *      @dev: device pointer
  *
  *     Allocate a special sound device by minor number from the sound
- *     subsystem. The allocated number is returned on succes. On failure
+ *     subsystem. The allocated number is returned on success. On failure
  *     a negative error code is returned.
  */
  
@@ -320,6 +384,9 @@ int register_sound_special_device(const struct file_operations *fops, int unit,
            case 4:
                name = "audio";
                break;
+           case 5:
+               name = "dspW";
+               break;
            case 8:
                name = "sequencer2";
                if (unit >= SOUND_STEP)
@@ -491,19 +558,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;
@@ -525,8 +579,6 @@ static int soundcore_open(struct inode *inode, struct file *file)
        struct sound_unit *s;
        const struct file_operations *new_fops = NULL;
 
-       lock_kernel ();
-
        chain=unit&0x0F;
        if(chain==4 || chain==5)        /* dsp/audio/dsp16 */
        {
@@ -539,7 +591,7 @@ 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);
 
                /*
@@ -579,18 +631,19 @@ static int soundcore_open(struct inode *inode, struct file *file)
                const struct file_operations *old_fops = file->f_op;
                file->f_op = new_fops;
                spin_unlock(&sound_loader_lock);
-               if(file->f_op->open)
+
+               if (file->f_op->open)
                        err = file->f_op->open(inode,file);
+
                if (err) {
                        fops_put(file->f_op);
                        file->f_op = fops_get(old_fops);
                }
+
                fops_put(old_fops);
-               unlock_kernel();
                return err;
        }
        spin_unlock(&sound_loader_lock);
-       unlock_kernel();
        return -ENODEV;
 }
 
@@ -605,7 +658,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;
        }