fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / sound / oss / sb_card.c
index b5f5ecb..8666291 100644 (file)
  * 02-07-2003 Bug made it into first release. Take two.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif /* CONFIG_MCA */
 #include "sound_config.h"
 #include "sb_mixer.h"
 #include "sb.h"
@@ -52,9 +48,10 @@ static int __initdata esstype   = 0; /* ESS chip type */
 static int __initdata acer     = 0; /* Do acer notebook init? */
 static int __initdata sm_games         = 0; /* Logitech soundman games? */
 
-struct sb_card_config *legacy = NULL;
+static struct sb_card_config *legacy = NULL;
 
 #ifdef CONFIG_PNP
+static int pnp_registered;
 static int __initdata pnp       = 1;
 /*
 static int __initdata uart401  = 0;
@@ -100,7 +97,14 @@ MODULE_PARM_DESC(uart401,  "When set to 1, will attempt to detect and enable"\
 /* OSS subsystem card registration shared by PnP and legacy routines */
 static int sb_register_oss(struct sb_card_config *scc, struct sb_module_options *sbmo)
 {
-       if(!sb_dsp_detect(&scc->conf, 0, 0, sbmo)) {
+       if (!request_region(scc->conf.io_base, 16, "soundblaster")) {
+               printk(KERN_ERR "sb: ports busy.\n");
+               kfree(scc);
+               return -EBUSY;
+       }
+
+       if (!sb_dsp_detect(&scc->conf, 0, 0, sbmo)) {
+               release_region(scc->conf.io_base, 16);
                printk(KERN_ERR "sb: Failed DSP Detect.\n");
                kfree(scc);
                return -ENODEV;
@@ -129,7 +133,7 @@ static void sb_unload(struct sb_card_config *scc)
 }
 
 /* Register legacy card with OSS subsystem */
-static int sb_init_legacy(void)
+static int __init sb_init_legacy(void)
 {
        struct sb_module_options sbmo = {0};
 
@@ -230,6 +234,8 @@ static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc)
        }
 }
 
+static unsigned int sb_pnp_devices;
+
 /* Probe callback function for the PnP API */
 static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id)
 {
@@ -260,6 +266,7 @@ static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device
               scc->conf.dma, scc->conf.dma2);
 
        pnp_set_card_drvdata(card, scc);
+       sb_pnp_devices++;
 
        return sb_register_oss(scc, &sbmo);
 }
@@ -282,8 +289,17 @@ static struct pnp_card_driver sb_pnp_driver = {
        .probe         = sb_pnp_probe,
        .remove        = sb_pnp_remove,
 };
+MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table);
 #endif /* CONFIG_PNP */
 
+static void __init_or_module sb_unregister_all(void)
+{
+#ifdef CONFIG_PNP
+       if (pnp_registered)
+               pnp_unregister_card_driver(&sb_pnp_driver);
+#endif
+}
+
 static int __init sb_init(void)
 {
        int lres = 0;
@@ -302,14 +318,21 @@ static int __init sb_init(void)
 
 #ifdef CONFIG_PNP
        if(pnp) {
-               pres = pnp_register_card_driver(&sb_pnp_driver);
+               int err = pnp_register_card_driver(&sb_pnp_driver);
+               if (!err)
+                       pnp_registered = 1;
+               pres = sb_pnp_devices;
        }
 #endif
        printk(KERN_INFO "sb: Init: Done\n");
 
        /* If either PnP or Legacy registered a card then return
         * success */
-       return (pres > 0 || lres > 0) ? 0 : -ENODEV;
+       if (pres == 0 && lres <= 0) {
+               sb_unregister_all();
+               return -ENODEV;
+       }
+       return 0;
 }
 
 static void __exit sb_exit(void)
@@ -322,14 +345,10 @@ static void __exit sb_exit(void)
                sb_unload(legacy);
        }
 
-#ifdef CONFIG_PNP
-       pnp_unregister_card_driver(&sb_pnp_driver);
-#endif
+       sb_unregister_all();
 
-       if (smw_free) {
-               vfree(smw_free);
-               smw_free = NULL;
-       }
+       vfree(smw_free);
+       smw_free = NULL;
 }
 
 module_init(sb_init);