fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / sound / oss / ad1848.c
index af1225d..7cf9913 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/ad1848.c
+ * sound/oss/ad1848.c
  *
  * The low level driver for the AD1848/CS4248 codec chip which
  * is used for example in the MS Sound System.
  *             Tested. Believed fully functional.
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
-#include <linux/pm.h>
 #include <linux/isapnp.h>
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
@@ -104,9 +102,6 @@ typedef struct
        int             irq_ok;
        mixer_ents     *mix_devices;
        int             mixer_output_port;
-
-       /* Power management */
-       struct          pm_dev *pmdev;
 } ad1848_info;
 
 typedef struct ad1848_port_info
@@ -123,9 +118,9 @@ ad1848_port_info;
 static struct address_info cfg;
 static int nr_ad1848_devs;
 
-int deskpro_xl;
-int deskpro_m;
-int soundpro;
+static int deskpro_xl;
+static int deskpro_m;
+static int soundpro;
 
 static volatile signed char irq2dev[17] = {
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -200,7 +195,7 @@ static void     ad1848_halt(int dev);
 static void     ad1848_halt_input(int dev);
 static void     ad1848_halt_output(int dev);
 static void     ad1848_trigger(int dev, int bits);
-static int     ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);
+static irqreturn_t adintr(int irq, void *dev_id);
 
 #ifndef EXCLUDE_TIMERS
 static int ad1848_tmr_install(int dev);
@@ -1538,7 +1533,7 @@ static void ad1848_init_hw(ad1848_info * devc)
        ad1848_mixer_reset(devc);
 }
 
-int ad1848_detect(int io_base, int *ad_flags, int *osp)
+int ad1848_detect(struct resource *ports, int *ad_flags, int *osp)
 {
        unsigned char tmp;
        ad1848_info *devc = &adev_info[nr_ad1848_devs];
@@ -1548,6 +1543,7 @@ int ad1848_detect(int io_base, int *ad_flags, int *osp)
        int ad1847_flag = 0;
        int cs4248_flag = 0;
        int sscape_flag = 0;
+       int io_base = ports->start;
 
        int i;
 
@@ -1578,11 +1574,6 @@ int ad1848_detect(int io_base, int *ad_flags, int *osp)
                printk(KERN_ERR "ad1848 - Too many audio devices\n");
                return 0;
        }
-       if (check_region(io_base, 4))
-       {
-               printk(KERN_ERR "ad1848.c: Port %x not free.\n", io_base);
-               return 0;
-       }
        spin_lock_init(&devc->lock);
        devc->base = io_base;
        devc->irq_ok = 0;
@@ -1951,7 +1942,7 @@ int ad1848_detect(int io_base, int *ad_flags, int *osp)
        return 1;
 }
 
-int ad1848_init (char *name, int io_base, int irq, int dma_playback,
+int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback,
                int dma_capture, int share_dma, int *osp, struct module *owner)
 {
        /*
@@ -1986,8 +1977,7 @@ int ad1848_init (char *name, int io_base, int irq, int dma_playback,
                sprintf(dev_name,
                        "Generic audio codec (%s)", devc->chip_name);
 
-       if (!request_region(devc->base, 4, devc->name))
-               return -1;
+       rename_region(ports, devc->name);
 
        conf_printf2(dev_name, devc->base, devc->irq, dma_playback, dma_capture);
 
@@ -2002,7 +1992,7 @@ int ad1848_init (char *name, int io_base, int irq, int dma_playback,
                        devc->audio_flags |= DMA_DUPLEX;
        }
 
-       portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
+       portc = kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
        if(portc==NULL) {
                release_region(devc->base, 4);
                return -1;
@@ -2031,16 +2021,13 @@ int ad1848_init (char *name, int io_base, int irq, int dma_playback,
 
        nr_ad1848_devs++;
 
-       devc->pmdev = pm_register(PM_ISA_DEV, my_dev, ad1848_pm_callback);
-       if (devc->pmdev)
-               devc->pmdev->data = devc;
-
        ad1848_init_hw(devc);
 
        if (irq > 0)
        {
                devc->dev_no = my_dev;
-               if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0)
+               if (request_irq(devc->irq, adintr, 0, devc->name,
+                               (void *)(long)my_dev) < 0)
                {
                        printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n");
                        /* Don't free it either then.. */
@@ -2183,14 +2170,13 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                
        if (devc != NULL)
        {
-               if(audio_devs[dev]->portc!=NULL)
-                       kfree(audio_devs[dev]->portc);
+               kfree(audio_devs[dev]->portc);
                release_region(devc->base, 4);
 
                if (!share_dma)
                {
                        if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
-                               free_irq(devc->irq, (void *)devc->dev_no);
+                               free_irq(devc->irq, (void *)(long)devc->dev_no);
 
                        sound_free_dma(dma_playback);
 
@@ -2202,9 +2188,6 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                if(mixer>=0)
                        sound_unload_mixerdev(mixer);
 
-               if (devc->pmdev)
-                       pm_unregister(devc->pmdev);
-
                nr_ad1848_devs--;
                for ( ; i < nr_ad1848_devs ; i++)
                        adev_info[i] = adev_info[i+1];
@@ -2213,7 +2196,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
 }
 
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t adintr(int irq, void *dev_id)
 {
        unsigned char status;
        ad1848_info *devc;
@@ -2222,7 +2205,7 @@ irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
        unsigned char c930_stat = 0;
        int cnt = 0;
 
-       dev = (int)dev_id;
+       dev = (long)dev_id;
        devc = (ad1848_info *) audio_devs[dev]->devc;
 
 interrupt_again:               /* Jump back here if int status doesn't reset */
@@ -2522,21 +2505,16 @@ static int init_deskpro(struct address_info *hw_config)
        return 1;
 }
 
-int probe_ms_sound(struct address_info *hw_config)
+int probe_ms_sound(struct address_info *hw_config, struct resource *ports)
 {
        unsigned char   tmp;
 
        DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype));
 
-       if (check_region(hw_config->io_base, 8))
-       {
-               printk(KERN_ERR "MSS: I/O port conflict\n");
-               return 0;
-       }
        if (hw_config->card_subtype == 1)       /* Has no IRQ/DMA registers */
        {
                /* check_opl3(0x388, hw_config); */
-               return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
+               return ad1848_detect(ports, NULL, hw_config->osp);
        }
 
        if (deskpro_xl && hw_config->card_subtype == 2) /* Compaq Deskpro XL */
@@ -2562,7 +2540,7 @@ int probe_ms_sound(struct address_info *hw_config)
                  int             ret;
 
                  DDB(printk("I/O address is inactive (%x)\n", tmp));
-                 if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp)))
+                 if (!(ret = ad1848_detect(ports, NULL, hw_config->osp)))
                          return 0;
                  return 1;
        }
@@ -2575,7 +2553,7 @@ int probe_ms_sound(struct address_info *hw_config)
 
                MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3)));
                DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n"));
-               if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp)))
+               if (!(ret = ad1848_detect(ports, NULL, hw_config->osp)))
                        return 0;
 
                hw_config->card_subtype = 1;
@@ -2610,10 +2588,10 @@ int probe_ms_sound(struct address_info *hw_config)
                printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
                return 0;
        }
-       return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
+       return ad1848_detect(ports, NULL, hw_config->osp);
 }
 
-void attach_ms_sound(struct address_info *hw_config, struct module *owner)
+void attach_ms_sound(struct address_info *hw_config, struct resource *ports, struct module *owner)
 {
        static signed char interrupt_bits[12] =
        {
@@ -2634,13 +2612,12 @@ void attach_ms_sound(struct address_info *hw_config, struct module *owner)
 
        if (hw_config->card_subtype == 1)       /* Has no IRQ/DMA registers */
        {
-               hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
+               hw_config->slots[0] = ad1848_init("MS Sound System", ports,
                                                    hw_config->irq,
                                                    hw_config->dma,
                                                    hw_config->dma2, 0, 
                                                    hw_config->osp,
                                                    owner);
-               request_region(hw_config->io_base, 4, "WSS config");
                return;
        }
        /*
@@ -2651,6 +2628,8 @@ void attach_ms_sound(struct address_info *hw_config, struct module *owner)
        if (bits == -1)
        {
                printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);
+               release_region(ports->start, 4);
+               release_region(ports->start - 4, 4);
                return;
        }
        outb((bits | 0x40), config_port);
@@ -2694,12 +2673,11 @@ void attach_ms_sound(struct address_info *hw_config, struct module *owner)
 
        outb((bits | dma_bits[dma] | dma2_bit), config_port);   /* Write IRQ+DMA setup */
 
-       hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
+       hw_config->slots[0] = ad1848_init("MS Sound System", ports,
                                          hw_config->irq,
                                          dma, dma2, 0,
                                          hw_config->osp,
                                          THIS_MODULE);
-       request_region(hw_config->io_base, 4, "WSS config");
 }
 
 void unload_ms_sound(struct address_info *hw_config)
@@ -2821,90 +2799,10 @@ static int ad1848_tmr_install(int dev)
 }
 #endif /* EXCLUDE_TIMERS */
 
-static int ad1848_suspend(ad1848_info *devc)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&devc->lock,flags);
-
-       ad_mute(devc);
-       
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return 0;
-}
-
-static int ad1848_resume(ad1848_info *devc)
-{
-       int mixer_levels[32], i;
-
-       /* Thinkpad is a bit more of PITA than normal. The BIOS tends to
-          restore it in a different config to the one we use.  Need to
-          fix this somehow */
-
-       /* store old mixer levels */
-       memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));  
-       ad1848_init_hw(devc);
-
-       /* restore mixer levels */
-       for (i = 0; i < 32; i++)
-               ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]);
-
-       if (!devc->subtype) {
-               static signed char interrupt_bits[12] = { -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 };
-               static char dma_bits[4] = { 1, 2, 0, 3 };
-               unsigned long flags;
-               signed char bits;
-               char dma2_bit = 0;
-
-               int config_port = devc->base + 0;
-
-               bits = interrupt_bits[devc->irq];
-               if (bits == -1) {
-                       printk(KERN_ERR "MSS: Bad IRQ %d\n", devc->irq);
-                       return -1;
-               }
-
-               spin_lock_irqsave(&devc->lock,flags);
-       
-               outb((bits | 0x40), config_port); 
-
-               if (devc->dma2 != -1 && devc->dma2 != devc->dma1)
-                       if ( (devc->dma1 == 0 && devc->dma2 == 1) ||
-                            (devc->dma1 == 1 && devc->dma2 == 0) ||
-                            (devc->dma1 == 3 && devc->dma2 == 0))
-                               dma2_bit = 0x04;
-
-               outb((bits | dma_bits[devc->dma1] | dma2_bit), config_port);
-               spin_unlock_irqrestore(&devc->lock,flags);
-       }
-
-       return 0;
-}
-
-static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) 
-{
-       ad1848_info *devc = dev->data;
-       if (devc) {
-               DEB(printk("ad1848: pm event received: 0x%x\n", rqst));
-
-               switch (rqst) {
-               case PM_SUSPEND:
-                       ad1848_suspend(devc);
-                       break;
-               case PM_RESUME:
-                       ad1848_resume(devc);
-                       break;
-               }
-       }
-       return 0;
-}
-
-
 EXPORT_SYMBOL(ad1848_detect);
 EXPORT_SYMBOL(ad1848_init);
 EXPORT_SYMBOL(ad1848_unload);
 EXPORT_SYMBOL(ad1848_control);
-EXPORT_SYMBOL(adintr);
 EXPORT_SYMBOL(probe_ms_sound);
 EXPORT_SYMBOL(attach_ms_sound);
 EXPORT_SYMBOL(unload_ms_sound);
@@ -2915,24 +2813,24 @@ static int __initdata dma = -1;
 static int __initdata dma2 = -1;
 static int __initdata type = 0;
 
-MODULE_PARM(io, "i");                   /* I/O for a raw AD1848 card */
-MODULE_PARM(irq, "i");                  /* IRQ to use */
-MODULE_PARM(dma, "i");                  /* First DMA channel */
-MODULE_PARM(dma2, "i");                 /* Second DMA channel */
-MODULE_PARM(type, "i");                 /* Card type */
-MODULE_PARM(deskpro_xl, "i");           /* Special magic for Deskpro XL boxen */
-MODULE_PARM(deskpro_m, "i");            /* Special magic for Deskpro M box */
-MODULE_PARM(soundpro, "i");             /* More special magic for SoundPro chips */
+module_param(io, int, 0);              /* I/O for a raw AD1848 card */
+module_param(irq, int, 0);             /* IRQ to use */
+module_param(dma, int, 0);             /* First DMA channel */
+module_param(dma2, int, 0);            /* Second DMA channel */
+module_param(type, int, 0);            /* Card type */
+module_param(deskpro_xl, bool, 0);     /* Special magic for Deskpro XL boxen */
+module_param(deskpro_m, bool, 0);      /* Special magic for Deskpro M box */
+module_param(soundpro, bool, 0);       /* More special magic for SoundPro chips */
 
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp,    "i");
-MODULE_PARM(isapnpjump,        "i");
-MODULE_PARM(reverse,   "i");
+module_param(isapnp, int, 0);
+module_param(isapnpjump, int, 0);
+module_param(reverse, bool, 0);
 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(reverse,      "When set to 1, will reverse ISAPnP search order");
 
-struct pnp_dev *ad1848_dev  = NULL;
+static struct pnp_dev  *ad1848_dev  = NULL;
 
 /* Please add new entries at the end of the table */
 static struct {
@@ -3002,7 +2900,8 @@ static struct pnp_dev *activate_dev(char *devname, char *resname, struct pnp_dev
        return(dev);
 }
 
-static struct pnp_dev *ad1848_init_generic(struct pnp_card *bus, struct address_info *hw_config, int slot)
+static struct pnp_dev __init *ad1848_init_generic(struct pnp_card *bus,
+                               struct address_info *hw_config, int slot)
 {
 
        /* Configure Audio device */
@@ -3095,6 +2994,7 @@ static int __init init_ad1848(void)
 #endif
 
        if(io != -1) {
+               struct resource *ports;
                if( isapnp == 0 )
                {
                        if(irq == -1 || dma == -1) {
@@ -3109,9 +3009,22 @@ static int __init init_ad1848(void)
                        cfg.card_subtype = type;
                }
 
-               if(!probe_ms_sound(&cfg))
+               ports = request_region(io + 4, 4, "ad1848");
+
+               if (!ports)
+                       return -EBUSY;
+
+               if (!request_region(io, 4, "WSS config")) {
+                       release_region(io + 4, 4);
+                       return -EBUSY;
+               }
+
+               if (!probe_ms_sound(&cfg, ports)) {
+                       release_region(io + 4, 4);
+                       release_region(io, 4);
                        return -ENODEV;
-               attach_ms_sound(&cfg, THIS_MODULE);
+               }
+               attach_ms_sound(&cfg, ports, THIS_MODULE);
                loaded = 1;
        }
        return 0;