Hello again,

Overview: This patch cleans up sb_card.c in a big way and provides for
handling of multiple pnp cards in one instance of the driver. Its still
against 2.3.99pre3 vanilla. I've gziped the patch because it is growing
rather large. Alex, I'll wait to diff against your patch until Linus
releases a new kernel with it in.

Ok, this time no new features, just bug fixes. Gael Queri brought to my
attention these things that I missed when merging the various sb_init
functions. Cards without a DMA2 should be properly handled now. The only
two such beasts I know of are the ALS007 and the Diamond card. If there
are others please let me know.  Also the resource index for the mpu io is
different on ESS and CTL cards, that is handled properly now, too. Some sb
compatables reverse the location of dma and dma2 in the isapnp resources,
now handled properly. Finally, some cards have a mpu irq. I'm not sure
exactly which cards do, I know the CMI card does, and from what Gael said
I'm pretty sure the ALS cards do. No clue about the Diamond card, though.
And since I don't have such a card I could not test to make sure this code
is correct.

Please try this one with every sb compatable pnp card you have (all in at
the same time, even), and let me know how it goes.  

BTW, its really late so I hope I didn't overlook something obvious.

Thanks again,
Paul Laufer
--- linux-devel-virgin/drivers/sound/sb_card.c  Sat Mar 25 15:52:34 2000
+++ linux/drivers/sound/sb_card.c       Tue Mar 28 00:39:29 2000
@@ -31,7 +31,10 @@
  *
  * 13-03-2000 Added some more cards, thanks to Torsten Werner.
  *  Removed joystick and wavetable code, there are better places for them.
- *  Code cleanup plus some fixes. 
+ *  Code cleanup plus some fixes.
+ *
+ * 27-03-2000 Big code cleanup and reorganization. ISAPnP multiple
+ *  card detection. Paul Laufer <[EMAIL PROTECTED]>
  *
  */
 
@@ -47,7 +50,14 @@
 #include "sb_mixer.h"
 #include "sb.h"
 
-static int sbmpu = 0;
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+#define SB_CARDS_MAX 4
+#else
+#define SB_CARDS_MAX 1
+#endif
+
+static int sbmpu[SB_CARDS_MAX] = {0};
+static int sb_cards_num = 0;
 
 extern void *smw_free;
 
@@ -55,7 +65,6 @@
 {
        if(!sb_dsp_init(hw_config))
                hw_config->slots[0] = -1;
-       SOUND_LOCK;
 }
 
 static int __init probe_sb(struct address_info *hw_config)
@@ -126,30 +135,22 @@
                }
        }
 #endif
-
-       /* This is useless since is done by sb_dsp_detect - azummo */
-       
-       if (check_region(hw_config->io_base, 16))
-       {
-               printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", 
hw_config->io_base);
-               return 0;
-       }
        return sb_dsp_detect(hw_config, 0, 0);
 }
 
-static void __exit unload_sb(struct address_info *hw_config)
+static void __exit unload_sb(struct address_info *hw_config, int card)
 {
        if(hw_config->slots[0]!=-1)
-               sb_dsp_unload(hw_config, sbmpu);
+               sb_dsp_unload(hw_config, sbmpu[card]);
 }
 
 extern int esstype;    /* ESS chip type */
 
-static struct address_info cfg;
-static struct address_info cfg_mpu;
+static struct address_info cfg[SB_CARDS_MAX];
+static struct address_info cfg_mpu[SB_CARDS_MAX];
 
-struct pci_dev         *sb_dev         = NULL, 
-               *mpu_dev        = NULL;
+struct pci_dev         *sb_dev[SB_CARDS_MAX]   = {NULL},
+               *mpu_dev[SB_CARDS_MAX]  = {NULL};
 /*
  *    Note DMA2 of -1 has the right meaning in the SB16 driver as well
  *    as here. It will cause either an error if it is needed or a fallback
@@ -167,9 +168,12 @@
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 static int isapnp      = 1;
 static int isapnpjump  = 0;
-static int activated   = 1;
+static int multiple    = 1;
+static int reverse     = 0;
+static int activated[SB_CARDS_MAX]    = {0};
 #else
 static int isapnp      = 0;
+static int multiple    = 0;
 #endif
 
 MODULE_DESCRIPTION("Soundblaster driver");
@@ -187,8 +191,12 @@
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 MODULE_PARM(isapnp,    "i");
 MODULE_PARM(isapnpjump,        "i");
+MODULE_PARM(multiple,  "i");
+MODULE_PARM(reverse,   "i");
 MODULE_PARM_DESC(isapnp,       "When set to 0, Plug & Play support will be 
disabled");
 MODULE_PARM_DESC(isapnpjump,   "Jumps to a specific slot in the driver's PnP table. 
Use the source, Luke.");
+MODULE_PARM_DESC(multiple,     "When set to 0, will not search for multiple cards");
+MODULE_PARM_DESC(reverse,      "When set to 1, will reverse ISAPnP search order");
 #endif
 
 MODULE_PARM_DESC(io,           "Soundblaster i/o base address 
(0x220,0x240,0x260,0x280)");
@@ -203,23 +211,215 @@
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 
+/* Please add new entries at the end of the table */
+static struct {
+       char *name; 
+       unsigned short card_vendor, card_device, audio_vendor, audio_function, 
+mpu_vendor, mpu_function;
+       short dma, dma2, mpu_io, mpu_irq; /* see sb_init() */
+} sb_isapnp_list[] __initdata = {
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0024),
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0026), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0027), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster Vibra16S", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster Vibra16C", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0070), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster Vibra16CL", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0080), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster Vibra16X", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00F0), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0039), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0042), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0043), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044),
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0054), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009C), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64 Gold",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C3), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C5), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C7), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+               0,0,
+               0,1,1,-1},
+       {"Sound Blaster AWE 64",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+               0,0,
+               0,1,1,-1},
+       {"ESS 1868",
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868),
+               0,0,
+               0,1,2,-1},
+       {"ESS 1868",
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611),
+               0,0,
+               0,1,2,-1},
+       {"ESS 1869 PnP AudioDrive", 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0003), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
+               0,0,
+               0,1,2,-1},
+       {"ESS 1869",
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1869), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
+               0,0,
+               0,1,2,-1},
+       {"ESS 1878",
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1878), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878),
+               0,0,
+               0,1,2,-1},
+       {"ESS 1879",
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1879), 
+               ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879),
+               0,0,
+               0,1,2,-1},
+       {"CMI 8330 SoundPRO",
+               ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), 
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+               ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+               0,1,0,0},
+       {"Diamond DT0197H",
+               ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688), 
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+               0,-1,0,-1},
+       {"ALS007",
+               ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+               0,-1,0,0},
+       {"ALS100",
+               ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), 
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+               1,0,0,0},
+       {"ALS110",
+               ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x1001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x1001),
+               1,0,0,0},
+       {"ALS120",
+               ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
+               1,0,0,0},
+       {"ALS200",
+               ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0020),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0020),
+               1,0,0,0},
+       {"RTL3000",
+               ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
+               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
+               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
+               1,0,0,0},
+       {0}
+};
+
 /* That's useful. */
 
 #define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located 
at %#lx\n", devname, resname, (resptr)->start)
 
-static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev 
*dev)
+static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev 
+*dev, int card)
 {
        int err;
 
        /* Device already active? Let's use it */
-
-       if(dev->active)
-       {
-               activated = 0;
+       if(dev->active) {
+               activated[card] = 1;
                return(dev);
        }
-       if((err = dev->activate(dev)) < 0)
-       {
+       
+       if((err = dev->activate(dev)) < 0) {
                printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", 
devname, resname, err);
 
                dev->deactivate(dev);
@@ -229,320 +429,108 @@
        return(dev);
 }
 
-/* Card's specific initialization functions
- */
-
-static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, 
struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init(struct pci_bus *bus, struct address_info *hw_config, 
+struct address_info *mpu_config, int slot, int card)
 {
-       if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
-       {
-               sb_dev->prepare(sb_dev);
+       /* Configure Audio device */
 
-               if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev)))
-               {
-                       hw_config->io_base      = sb_dev->resource[0].start;
-                       hw_config->irq          = sb_dev->irq_resource[0].start;
-                       hw_config->dma          = sb_dev->dma_resource[0].start;
-                       hw_config->dma2         = sb_dev->dma_resource[1].start;
-                       mpu_config->io_base     = sb_dev->resource[1].start;
-               }
-       }
-       return(sb_dev);
-}
-
-static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct 
address_info *hw_config, struct address_info *mpu_config)
-{
-       if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
+       if((sb_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].audio_vendor, 
+sb_isapnp_list[slot].audio_function, NULL)))
        {
-               sb_dev->prepare(sb_dev);
+               sb_dev[card]->prepare(sb_dev[card]);
 
-               if((sb_dev = activate_dev("ESS", "sb", sb_dev)))
+               if((sb_dev[card] = activate_dev(sb_isapnp_list[slot].name, "sb", 
+sb_dev[card], card)))
                {
-                       hw_config->io_base      = sb_dev->resource[0].start;
-                       hw_config->irq          = sb_dev->irq_resource[0].start;
-                       hw_config->dma          = sb_dev->dma_resource[0].start;
-                       hw_config->dma2         = sb_dev->dma_resource[1].start;
-                       mpu_config->io_base     = sb_dev->resource[2].start;
-               }
-       }
-       return(sb_dev);
-}
-
-static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct 
address_info *hw_config, struct address_info *mpu_config)
-{
-       /* 
-        *  The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ 
?
-        *  It's ISAPnP section is badly designed and has many flaws, i'll do my best
-        *  to workaround them. I strongly suggest you to buy a real soundcard.
-        *  The CMI8330 on my motherboard has also the bad habit to activate 
-        *  the rear channel of my amplifier instead of the front one.
-        */
-
-       /*  @X@0001:Soundblaster.
-        */
-
-       if((sb_dev = isapnp_find_dev(bus,
-               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-       {
-               sb_dev->prepare(sb_dev);
-               
-               if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
-               {
-                       hw_config->io_base      = sb_dev->resource[0].start;
-                       hw_config->irq          = sb_dev->irq_resource[0].start;
-                       hw_config->dma          = sb_dev->dma_resource[0].start;
-                       hw_config->dma2         = sb_dev->dma_resource[1].start;
-
-                       show_base("CMI8330", "sb", &sb_dev->resource[0]);
-               }
+                       hw_config->io_base      = sb_dev[card]->resource[0].start;
+                       hw_config->irq          = sb_dev[card]->irq_resource[0].start;
+                       hw_config->dma          = 
+sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma].start;
+                       if(sb_isapnp_list[slot].dma2 != -1)
+                               hw_config->dma2 = 
+sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma2].start;
+                       else
+                               hw_config->dma2 = -1;
+               } else
+                       return(NULL);
+       } else
+               return(NULL);
 
-               if(!sb_dev) return(NULL);
+       /* Cards with MPU part of Audio device */
+       
+       if(!sb_isapnp_list[slot].mpu_vendor) {
+               mpu_config->io_base     = 
+sb_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
+               return(sb_dev[card]);
        }
-       else
-               printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n");
 
-       /*  @H@0001:mpu
-        */
+       /* Cards with separate MPU device */
 
-       if((mpu_dev = isapnp_find_dev(bus,
-               ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+       if((mpu_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].mpu_vendor, 
+sb_isapnp_list[slot].mpu_function, NULL)))
        {
-               mpu_dev->prepare(mpu_dev);
-
-               /*  This disables the interrupt on this resource. Do we need it ?
-                */
-
-               mpu_dev->irq_resource[0].flags = 0;
+               mpu_dev[card]->prepare(mpu_dev[card]);
 
-               if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev)))
-               {
-                       show_base("CMI8330", "mpu", &mpu_dev->resource[0]);
-                       mpu_config->io_base = mpu_dev->resource[0].start;
+               if((mpu_dev[card] = activate_dev(sb_isapnp_list[slot].name, "mpu", 
+mpu_dev[card], card))) {
+                       mpu_config->io_base = 
+mpu_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
+                       if(sb_isapnp_list[slot].mpu_irq != -1)
+                               mpu_config->irq = 
+sb_dev[card]->irq_resource[sb_isapnp_list[slot].mpu_irq].start;
                }
        }
        else
-               printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
-
-       printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo 
<[EMAIL PROTECTED]>\n");
-
-       return(sb_dev);
+               printk(KERN_ERR "sb: %s panic: mpu not found\n", 
+sb_isapnp_list[slot].name);
+       
+       return(sb_dev[card]);
 }
 
-static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card, 
struct address_info *hw_config, struct address_info *mpu_config)
+static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info 
+*mpu_config, struct pci_bus *bus, int slot, int card)
 {
-       /* 
-        * Diamonds DT0197H
-        * very similar to the CMI8330 above
-        */
-
-       /*  @@@0001:Soundblaster.
-        */
-
-       if((sb_dev = isapnp_find_dev(bus,
-                               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 
NULL)))
-       {
-               sb_dev->prepare(sb_dev);
-               
-               if((sb_dev = activate_dev("DT0197H", "sb", sb_dev)))
-               {
-                       hw_config->io_base      = sb_dev->resource[0].start;
-                       hw_config->irq          = sb_dev->irq_resource[0].start;
-                       hw_config->dma          = sb_dev->dma_resource[0].start;
-                       hw_config->dma2         = -1;
-
-                       show_base("DT0197H", "sb", &sb_dev->resource[0]);
-               }
-
-               if(!sb_dev) return(NULL);
-       }
-       else
-               printk(KERN_ERR "sb: DT0197H panic: sb base not found\n");
-
-       /*  @X@0001:mpu
-        */
-
-       if((mpu_dev = isapnp_find_dev(bus,
-                               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 
NULL)))
-       {
-               mpu_dev->prepare(mpu_dev);
-
-               if((mpu_dev = activate_dev("DT0197H", "mpu", mpu_dev)))
-               {
-                       show_base("DT0197H", "mpu", &mpu_dev->resource[0]);
-                       mpu_config->io_base = mpu_dev->resource[0].start;
-               }
-       }
-       else
-               printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-
-       printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner 
<[EMAIL PROTECTED]>\n");
-
-       return(sb_dev);
-}
+       char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
 
-static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct 
address_info *hw_config, struct address_info *mpu_config)
-{
-       /* 
-        * ALS100
-        * very similar to both ones above above
-        */
+       printk(KERN_INFO "sb: %s detected\n", busname); 
 
-       /*  @@@0001:Soundblaster.
-        */
+       /* Initialize this baby. */
 
-       if((sb_dev = isapnp_find_dev(bus,
-                               ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 
NULL)))
-       {
-               sb_dev->prepare(sb_dev);
+       if(sb_init(bus, hw_config, mpu_config, slot, card)) {
+               /* We got it. */
                
-               if((sb_dev = activate_dev("ALS100", "sb", sb_dev)))
-               {
-                       hw_config->io_base      = sb_dev->resource[0].start;
-                       hw_config->irq          = sb_dev->irq_resource[0].start;
-                       hw_config->dma          = sb_dev->dma_resource[1].start;
-                       hw_config->dma2         = sb_dev->dma_resource[0].start;
-
-                       show_base("ALS100", "sb", &sb_dev->resource[0]);
-               }
-
-               if(!sb_dev) return(NULL);
-       }
-       else
-               printk(KERN_ERR "sb: ALS100 panic: sb base not found\n");
-
-       /*  @X@0001:mpu
-        */
-
-       if((mpu_dev = isapnp_find_dev(bus,
-                               ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 
NULL)))
-       {
-               mpu_dev->prepare(mpu_dev);
-
-               if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev)))
-               {
-                       show_base("ALS100", "mpu", &mpu_dev->resource[0]);
-                       mpu_config->io_base = mpu_dev->resource[0].start;
-               }
-       }
-       else
-               printk(KERN_ERR "sb: ALS100 panic: mpu not found\n");
-
-       printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner 
<[EMAIL PROTECTED]>\n");
-
-       return(sb_dev);
-}
-
-#define SBF_DEV        0x01 /* Please notice that cards without this flag are on the 
top in the list */
-
-
-static struct { unsigned short vendor, function, flags; struct pci_dev * 
(*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct 
address_info *); char *name; }
-sb_isapnp_list[] __initdata = {
-       {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0,        &sb_init_cmi,  
         "CMI 8330 SoundPRO" },
-       {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0,        
&sb_init_diamond,       "Diamond DT0197H" },
-       {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0,        &sb_init_als,  
         "ALS 100" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV,  
&sb_init_generic,       "Sound Blaster 16" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV,  &sb_init_ess,  
         "ESS 1688" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV,  &sb_init_ess,  
         "ESS 1868" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV,  &sb_init_ess,  
         "ESS 1868" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV,  &sb_init_ess,  
         "ESS 1869" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV,  &sb_init_ess,  
         "ESS 1878" },
-       {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV,  &sb_init_ess,  
         "ESS 1879" },
-       {0}
-};
-
-static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info 
*mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
-{
-       struct pci_dev *idev = NULL;
-
-       /* You missed the init func? That's bad. */
-       if(sb_isapnp_list[slot].initfunc)
-       {
-               char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
-
-               printk(KERN_INFO "sb: %s detected\n", busname); 
-
-               /* Initialize this baby. */
-
-               if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, 
mpu_config)))
-               {
-                       /* We got it. */
-
-                       printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq 
%d, dma %d, %d\n",
-                              busname,
-                              hw_config->io_base, hw_config->irq, hw_config->dma,
-                              hw_config->dma2);
-                       return 1;
-               }
-               else
-                       printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
+               printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma 
+%d, %d\n",
+                      busname,
+                      hw_config->io_base, hw_config->irq, hw_config->dma,
+                      hw_config->dma2);
+               return 1;
        }
        else
-               printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n");
+               printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
 
        return 0;
 }
 
-/* Actually this routine will detect and configure only the first card with 
successful
-   initialization. isapnpjump could be used to jump to a specific entry.
-   Please always add entries at the end of the array.
-   Should this be fixed? - azummo
-*/
-
-int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info 
*mpu_config) 
+int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info 
+*mpu_config, int card) 
 {
+       static int first = 1;
        int i;
 
        /* Count entries in sb_isapnp_list */
-       for (i = 0; sb_isapnp_list[i].vendor != 0; i++);
+       for (i = 0; sb_isapnp_list[i].card_vendor != 0; i++);
+       i--;
 
        /* Check and adjust isapnpjump */
-       if( isapnpjump < 0 || isapnpjump > ( i - 1 ) )
-       {
-               printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to 
0.\n", i-1);
-               isapnpjump = 0;
+       if( isapnpjump < 0 || isapnpjump > i) {
+               isapnpjump = reverse ? i : 0;
+               printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to 
+%d.\n", i, isapnpjump);
        }
-       
-       for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
 
-               if(!(sb_isapnp_list[i].flags & SBF_DEV))
-               {
-                       struct pci_bus *bus = NULL;
-                               
-                       while ((bus = isapnp_find_card(
-                                       sb_isapnp_list[i].vendor,
-                                       sb_isapnp_list[i].function,
-                                       bus))) {
+       if(!first || !reverse)
+               i = isapnpjump;
+       first = 0;
+       while(sb_isapnp_list[i].card_vendor != 0) {
+               static struct pci_bus *bus = NULL;
+
+               while ((bus = isapnp_find_card(
+                               sb_isapnp_list[i].card_vendor,
+                               sb_isapnp_list[i].card_device,
+                               bus))) {
        
-                               if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, 
i))
-                                       return 0;
-                       }
-               }
-       }
-
-       /*  No cards found. I'll try now to search inside every card for a logical 
device
-        *  that matches any entry marked with SBF_DEV in the table.
-        */
-
-       for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
-
-               if(sb_isapnp_list[i].flags & SBF_DEV)
-               {
-                       struct pci_dev *card = NULL;
-
-                       while ((card = isapnp_find_dev(NULL,
-                                       sb_isapnp_list[i].vendor,
-                                       sb_isapnp_list[i].function,
-                                       card))) {
-
-                               if(sb_isapnp_init(hw_config, mpu_config, card->bus, 
card, i))
-                                       return 0;
+                       if(sb_isapnp_init(hw_config, mpu_config, bus, i, card)) {
+                               isapnpjump = i; /* start next search from here */
+                               return 0;
                        }
                }
+               i += reverse ? -1 : 1;          
        }
 
        return -ENODEV;
@@ -551,62 +539,77 @@
 
 static int __init init_sb(void)
 {
-       printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 
1993-1996\n");
+       int card, max = multiple ? SB_CARDS_MAX : 1;
 
-       /* Please remember that even with CONFIG_ISAPNP defined one should still be
-               able to disable PNP support for this single driver!
-       */
-
-#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE                      
-       if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) {
-               printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard 
ones...\n");
-               isapnp = 0;
-       }
+       printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 
+1993-1996\n");
+       
+       for(card = 0; card < max; card++, sb_cards_num++) {
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+               /* Please remember that even with CONFIG_ISAPNP defined one should 
+still be
+                  able to disable PNP support for this single driver! */
+               if(isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) 
+{
+                       if(sb_cards_num == 0) {
+                               printk(KERN_NOTICE "sb_card: No ISAPnP cards found, 
+trying standard ones...\n");
+                               isapnp = 0;
+                       } else
+                               break;
+               }
 #endif
 
-       if( isapnp == 0 ) {
-               cfg.io_base     = io;
-               cfg.irq         = irq;
-               cfg.dma         = dma;
-               cfg.dma2        = dma16;
-       }
+               if( isapnp == 0 && sb_cards_num == 0) {
+                       cfg[card].io_base       = io;
+                       cfg[card].irq           = irq;
+                       cfg[card].dma           = dma;
+                       cfg[card].dma2  = dma16;
+               }
 
-       cfg.card_subtype = type;
+               cfg[card].card_subtype = type;
 
-       if (!probe_sb(&cfg))
-               return -ENODEV;
-       attach_sb_card(&cfg);
+               if (!probe_sb(&cfg[card]))
+                       return -ENODEV;
+               attach_sb_card(&cfg[card]);
 
-       if(cfg.slots[0]==-1)
-               return -ENODEV;
+               if(cfg[card].slots[0]==-1)
+                       return -ENODEV;
                
-       if (isapnp == 0) 
-               cfg_mpu.io_base = mpu_io;
-       if (probe_sbmpu(&cfg_mpu))
-               sbmpu = 1;
-       if (sbmpu)
-               attach_sbmpu(&cfg_mpu);
+               if (isapnp == 0) 
+                       cfg_mpu[card].io_base = mpu_io;
+               if (probe_sbmpu(&cfg_mpu[card]))
+                       sbmpu[card] = 1;
+               if (sbmpu[card])
+                       attach_sbmpu(&cfg_mpu[card]);
+       }
+
+       SOUND_LOCK;
+
+       if(isapnp)
+               printk(KERN_NOTICE "sb_card: %d Soundblaster PnP card(s) found.\n", 
+sb_cards_num);
+
        return 0;
 }
 
 static void __exit cleanup_sb(void)
 {
+       int i;
+       
        if (smw_free) {
                vfree(smw_free);
                smw_free = NULL;
        }
-       unload_sb(&cfg);
-       if (sbmpu)
-               unload_sbmpu(&cfg_mpu);
-       SOUND_LOCK_END;
 
-#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE                      
-       if(activated)
-       {
-               if(sb_dev)      sb_dev->deactivate(sb_dev);
-               if(mpu_dev)     mpu_dev->deactivate(mpu_dev);
-       }
+       for(i = 0; i < sb_cards_num; i++) {
+               unload_sb(&cfg[i], i);
+               if (sbmpu[i])
+                       unload_sbmpu(&cfg_mpu[i]);
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+               if(!activated[i]) {
+                       if(sb_dev[i])   sb_dev[i]->deactivate(sb_dev[i]);
+                       if(mpu_dev[i])  mpu_dev[i]->deactivate(mpu_dev[i]);
+               }
 #endif
+       }
+       SOUND_LOCK_END; 
 }
 
 module_init(init_sb);

Reply via email to