vserver 1.9.3
[linux-2.6.git] / sound / oss / sscape.c
index 733bfc1..7c9b5d4 100644 (file)
@@ -600,10 +600,10 @@ static coproc_operations sscape_coproc_operations =
        &adev_info
 };
 
-static int sscape_detected;
+static struct resource *sscape_ports;
 static int sscape_is_pnp;
 
-void __init attach_sscape(struct address_info *hw_config)
+static void __init attach_sscape(struct address_info *hw_config)
 {
 #ifndef SSCAPE_REGS
        /*
@@ -638,10 +638,6 @@ void __init attach_sscape(struct address_info *hw_config)
 
        int i, irq_bits = 0xff;
 
-       if (sscape_detected != hw_config->io_base)
-               return;
-
-       request_region(devc->base + 2, 6, "SoundScape");
        if (old_hardware)
        {
                valid_interrupts = valid_interrupts_old;
@@ -650,7 +646,7 @@ void __init attach_sscape(struct address_info *hw_config)
        else
                conf_printf("Ensoniq SoundScape", hw_config);
 
-       for (i = 0; i < sizeof(valid_interrupts); i++)
+       for (i = 0; i < 4; i++)
        {
                if (hw_config->irq == valid_interrupts[i])
                {
@@ -661,45 +657,32 @@ void __init attach_sscape(struct address_info *hw_config)
        if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
        {
                printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
+               release_region(devc->base, 2);
+               release_region(devc->base + 2, 6);
+               if (sscape_is_pnp)
+                       release_region(devc->codec, 2);
                return;
        }
        
        if (!sscape_is_pnp) {
        
                spin_lock_irqsave(&devc->lock,flags);
-           for (i = 1; i < 10; i++)
-           {
-               switch (i)
-               {
-                       case 1: /* Host interrupt enable */
-                               sscape_write(devc, i, 0xf0);    /* All interrupts enabled */
-                               break;
-
-                       case 2: /* DMA A status/trigger register */
-                       case 3: /* DMA B status/trigger register */
-                               sscape_write(devc, i, 0x20);    /* DMA channel disabled */
-                               break;
-
-                       case 4: /* Host interrupt config reg */
-                               sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits);
-                               break;
-
-                       case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */
-                               sscape_write(devc, i, (regs[i] & 0x3f) | (sscape_read(devc, i) & 0xc0));
-                               break;
-
-                       case 6: /* CD-ROM config (WSS codec actually) */
-                               sscape_write(devc, i, regs[i]);
-                               break;
-
-                       case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
-                               sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x08);
-                               break;
-
-                       default:
-                               sscape_write(devc, i, regs[i]);
-               }
-           }
+               /* Host interrupt enable */
+               sscape_write(devc, 1, 0xf0);    /* All interrupts enabled */
+               /* DMA A status/trigger register */
+               sscape_write(devc, 2, 0x20);    /* DMA channel disabled */
+               /* DMA B status/trigger register */
+               sscape_write(devc, 3, 0x20);    /* DMA channel disabled */
+               /* Host interrupt config reg */
+               sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits);
+               /* Don't destroy CD-ROM DMA config bits (0xc0) */
+               sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0));
+               /* CD-ROM config (WSS codec actually) */
+               sscape_write(devc, 6, regs[6]);
+               sscape_write(devc, 7, regs[7]);
+               sscape_write(devc, 8, regs[8]);
+               /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
+               sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08);
                spin_unlock_irqrestore(&devc->lock,flags);
        }
 #ifdef SSCAPE_DEBUG2
@@ -715,7 +698,7 @@ void __init attach_sscape(struct address_info *hw_config)
        }
 #endif
 
-       if (probe_mpu401(hw_config))
+       if (probe_mpu401(hw_config, sscape_ports))
                hw_config->always_detect = 1;
        hw_config->name = "SoundScape";
 
@@ -739,9 +722,6 @@ static int detect_ga(sscape_info * devc)
 
        DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base));
 
-       if (check_region(devc->base, 8))
-               return 0;
-
        /*
         * First check that the address register of "ODIE" is
         * there and that it has exactly 4 writable bits.
@@ -1115,9 +1095,9 @@ static void __init sscape_pnp_init_hw(sscape_info* devc)
                sscape_write( devc, 9, i | 3 );
                sscape_write( devc, 3, 0x40);
 
-               if (check_region(0x228, 1)) {
-                           outb(0, 0x228);
-                           release_region(0x228,1);
+               if (request_region(0x228, 1, "sscape setup junk")) {
+                       outb(0, 0x228);
+                       release_region(0x228,1);
                }
                sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
                sscape_write( devc, 9, i );
@@ -1134,50 +1114,46 @@ static int __init detect_sscape_pnp(sscape_info* devc)
 
        DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
 
-       if (check_region(devc->base, 8)) {
-               printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->base);        
-               return 0;
-       }
-               
-       if (check_region(devc->codec, 2)) {
+       if (!request_region(devc->codec, 2, "sscape codec")) {
                printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);       
                return 0;
        }
 
-       if ( (inb( devc -> base + 2) & 0x78) != 0) return 0;
+       if ((inb(devc->base + 2) & 0x78) != 0)
+               goto fail;
 
        d = inb ( devc -> base + 4) & 0xF0;
-       if (  (d & 0x80) != 0)  return 0;
+       if (d & 0x80)
+               goto fail;
        
        if (d == 0) {
-                       devc->codec_type = 1;
-                       devc->ic_type = IC_ODIE;
-       }
-       else if ( (d & 0x60) != 0) {
-                       devc->codec_type = 2;
-                       devc->ic_type = IC_OPUS;
-       }
-       else if ( (d & 0x40) != 0) {
-                       devc->codec_type = 2;
-                       devc->ic_type = IC_ODIE;
-       } 
-       else return 0;
+               devc->codec_type = 1;
+               devc->ic_type = IC_ODIE;
+       } else if ( (d & 0x60) != 0) {
+               devc->codec_type = 2;
+               devc->ic_type = IC_OPUS;
+       } else if ( (d & 0x40) != 0) {  /* WTF? */
+               devc->codec_type = 2;
+               devc->ic_type = IC_ODIE;
+       } else
+               goto fail;
        
        sscape_is_pnp = 1;
                
        outb(0xFA, devc -> base+4);
        if  ((inb( devc -> base+4) & 0x9F) != 0x0A)
-               return 0;
+               goto fail;
        outb(0xFE, devc -> base+4);
        if  ( (inb(devc -> base+4) & 0x9F) != 0x0E)
-               return 0;
+               goto fail;
        if  ( (inb(devc -> base+5) & 0x9F) != 0x0E)
-               return 0;
+               goto fail;
 
        if (devc->codec_type == 2) {
-               if (devc -> codec != devc -> base + 8)
+               if (devc->codec != devc->base + 8) {
                        printk("soundscape warning: incorrect codec port specified\n");
-               devc -> codec = devc -> base + 8;
+                       goto fail;
+               }
                d = 0x10 | (sscape_read(devc, 9)  & 0xCF);
                sscape_write(devc, 9, d);
                sscape_write(devc, 6, 0x80);
@@ -1193,9 +1169,9 @@ static int __init detect_sscape_pnp(sscape_info* devc)
 
        d = inb(devc -> codec);
        if (d & 0x80)
-               return 0;
+               goto fail;
        if ( inb(devc -> codec + 2) == 0xFF)
-               return 0;
+               goto fail;
 
        sscape_write(devc, 9, sscape_read(devc, 9)  & 0x3F );
 
@@ -1217,7 +1193,7 @@ static int __init detect_sscape_pnp(sscape_info* devc)
                
        sscape_pnp_init_hw(devc);
 
-       for (i = 0; i < sizeof(valid_interrupts); i++)
+       for (i = 0; i < 4; i++)
        {
                if (devc->codec_irq == valid_interrupts[i]) {
                        irq_bits = i;
@@ -1234,15 +1210,14 @@ static int __init detect_sscape_pnp(sscape_info* devc)
        sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
        sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
 
-       return 1;       
+       return 1;
+fail:
+       release_region(devc->codec, 2);
+       return 0;
 }
 
 static int __init probe_sscape(struct address_info *hw_config)
 {
-
-       if (sscape_detected != 0 && sscape_detected != hw_config->io_base)
-               return 0;
-
        devc->base = hw_config->io_base;
        devc->irq = hw_config->irq;
        devc->dma = hw_config->dma;
@@ -1262,12 +1237,21 @@ static int __init probe_sscape(struct address_info *hw_config)
 #endif
        devc->failed = 1;
 
+       sscape_ports = request_region(devc->base, 2, "mpu401");
+       if (!sscape_ports)
+               return 0;
+
+       if (!request_region(devc->base + 2, 6, "SoundScape")) {
+               release_region(devc->base, 2);
+               return 0;
+       }
+
        if (!detect_ga(devc)) {
-               if (detect_sscape_pnp(devc)) {                  
-                       sscape_detected = hw_config->io_base;
+               if (detect_sscape_pnp(devc))
                        return 1;
-               } 
-               else return 0;
+               release_region(devc->base, 2);
+               release_region(devc->base + 2, 6);
+               return 0;
        }
 
        if (old_hardware)       /* Check that it's really an old Spea/Reveal card. */
@@ -1282,14 +1266,14 @@ static int __init probe_sscape(struct address_info *hw_config)
                                inb(devc->base + ODIE_ADDR);
                }
        }
-       sscape_detected = hw_config->io_base;
        return 1;
 }
 
-static int __init probe_ss_ms_sound(struct address_info *hw_config)
+static int __init init_ss_ms_sound(struct address_info *hw_config)
 {
        int i, irq_bits = 0xff;
        int ad_flags = 0;
+       struct resource *ports;
        
        if (devc->failed)
        {
@@ -1301,7 +1285,7 @@ static int __init probe_ss_ms_sound(struct address_info *hw_config)
                printk(KERN_ERR "soundscape: Invalid initialization order.\n");
                return 0;
        }
-       for (i = 0; i < sizeof(valid_interrupts); i++)
+       for (i = 0; i < 4; i++)
        {
                if (hw_config->irq == valid_interrupts[i])
                {
@@ -1309,37 +1293,27 @@ static int __init probe_ss_ms_sound(struct address_info *hw_config)
                        break;
                }
        }
-       if (hw_config->irq > 15 || irq_bits == 0xff)
-       {
+       if (irq_bits == 0xff) {
                printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
                return 0;
        }
        
-       if (!sscape_is_pnp) {
-               if (old_hardware)
-                       ad_flags = 0x12345677;  /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
-               return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
-       } 
-       else {
-               if (old_hardware)
-                       ad_flags = 0x12345677;  /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
-               else
-                       ad_flags = 0x87654321;  /* Tell that we have a soundscape pnp with 1845 chip */
-               return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
-       }
-}
+       if (old_hardware)
+               ad_flags = 0x12345677;  /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+       else if (sscape_is_pnp)
+               ad_flags = 0x87654321;  /* Tell that we have a soundscape pnp with 1845 chip */
 
-static void __init attach_ss_ms_sound(struct address_info *hw_config)
-{
-       /*
-        * This routine configures the SoundScape card for use with the
-        * Win Sound System driver. The AD1848 codec interface uses the CD-ROM
-        * config registers of the "ODIE".
-        */
+       ports = request_region(hw_config->io_base, 4, "ad1848");
+       if (!ports) {
+               printk(KERN_ERR "soundscape: ports busy\n");
+               return 0;
+       }
 
-       int i, irq_bits = 0xff;
+       if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) {
+               release_region(hw_config->io_base, 4);
+               return 0;
+       }
 
-               
        if (!sscape_is_pnp)  /*pnp is already setup*/
        {
                /*
@@ -1355,14 +1329,6 @@ static void __init attach_ss_ms_sound(struct address_info *hw_config)
                /*
                 * Init the AD1848 (CD-ROM) config reg.
                 */
-               for (i = 0; i < sizeof(valid_interrupts); i++)
-               {
-                       if (hw_config->irq == valid_interrupts[i])
-                       {
-                               irq_bits = i;
-                               break;
-                       }
-               }       
                sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
        }
        
@@ -1371,7 +1337,7 @@ static void __init attach_ss_ms_sound(struct address_info *hw_config)
                                
        hw_config->slots[0] = ad1848_init(
                        sscape_is_pnp ? "SoundScape" : "SoundScape PNP",
-                       hw_config->io_base,
+                       ports,
                        hw_config->irq,
                        hw_config->dma,
                        hw_config->dma,
@@ -1402,13 +1368,15 @@ static void __init attach_ss_ms_sound(struct address_info *hw_config)
                        printk("I%d = %02x\n", i, sscape_read(devc, i));
        }
 #endif
-
+       return 1;
 }
 
 static void __exit unload_sscape(struct address_info *hw_config)
 {
        release_region(devc->base + 2, 6);
        unload_mpu401(hw_config);
+       if (sscape_is_pnp)
+               release_region(devc->codec, 2);
 }
 
 static void __exit unload_ss_ms_sound(struct address_info *hw_config)
@@ -1480,10 +1448,7 @@ static int __init init_sscape(void)
 
        attach_sscape(&cfg_mpu);
        
-       mss = probe_ss_ms_sound(&cfg);
-
-       if (mss)
-               attach_ss_ms_sound(&cfg);
+       mss = init_ss_ms_sound(&cfg);
 
        return 0;
 }