* 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>
int irq_ok;
mixer_ents *mix_devices;
int mixer_output_port;
-
- /* Power management */
- struct pm_dev *pmdev;
} ad1848_info;
typedef struct 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,
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);
#ifndef EXCLUDE_TIMERS
static int ad1848_tmr_install(int dev);
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];
int ad1847_flag = 0;
int cs4248_flag = 0;
int sscape_flag = 0;
+ int io_base = ports->start;
int i;
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;
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)
{
/*
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);
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.. */
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);
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];
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 */
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 */
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;
}
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;
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] =
{
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;
}
/*
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);
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)
}
#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);
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 {
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 */
#endif
if(io != -1) {
+ struct resource *ports;
if( isapnp == 0 )
{
if(irq == -1 || dma == -1) {
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;