clps711xfb: convert to proc_fops
[safe/jmp/linux-2.6] / sound / isa / es18xx.c
index a36ec1d..9a43baa 100644 (file)
  *   needed for ZV, so maybe the datasheet is entirely wrong here.
  */
  
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
 #include <linux/isapnp.h>
 #include <linux/moduleparam.h>
+#include <linux/delay.h>
+
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
 
 struct snd_es18xx {
        unsigned long port;             /* port of ESS chip */
-       unsigned long mpu_port;         /* MPU-401 port of ESS chip */
-       unsigned long fm_port;          /* FM port */
        unsigned long ctrl_port;        /* Control port of ESS chip */
        struct resource *res_port;
        struct resource *res_mpu_port;
@@ -115,12 +114,9 @@ struct snd_es18xx {
        unsigned short audio2_vol;      /* volume level of audio2 */
 
        unsigned short active;          /* active channel mask */
-       unsigned int dma1_size;
-       unsigned int dma2_size;
        unsigned int dma1_shift;
        unsigned int dma2_shift;
 
-       struct snd_card *card;
        struct snd_pcm *pcm;
        struct snd_pcm_substream *playback_a_substream;
        struct snd_pcm_substream *capture_a_substream;
@@ -135,14 +131,9 @@ struct snd_es18xx {
 
        spinlock_t reg_lock;
        spinlock_t mixer_lock;
-       spinlock_t ctrl_lock;
 #ifdef CONFIG_PM
        unsigned char pm_reg;
 #endif
-};
-
-struct snd_audiodrive {
-       struct snd_es18xx *chip;
 #ifdef CONFIG_PNP
        struct pnp_dev *dev;
        struct pnp_dev *devc;
@@ -161,7 +152,7 @@ struct snd_audiodrive {
 #define ES18XX_DUPLEX_SAME 0x0010      /* Playback and record must share the same rate */
 #define ES18XX_NEW_RATE        0x0020  /* More precise rate setting */
 #define ES18XX_AUXB    0x0040  /* AuxB mixer control */
-#define ES18XX_HWV     0x0080  /* Has seperate hardware volume mixer controls*/
+#define ES18XX_HWV     0x0080  /* Has separate hardware volume mixer controls*/
 #define ES18XX_MONO    0x0100  /* Mono_in mixer control */
 #define ES18XX_I2S     0x0200  /* I2S mixer control */
 #define ES18XX_MUTEREC 0x0400  /* Record source can be muted */
@@ -358,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch
 }
 
 
-static int snd_es18xx_reset(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_reset(struct snd_es18xx *chip)
 {
        int i;
         outb(0x03, chip->port + 0x06);
@@ -494,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip,
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma2_size = size;
-
         snd_es18xx_rate_set(chip, substream, DAC2);
 
         /* Transfer Count Reload */
@@ -595,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma1_size = size;
-
        snd_es18xx_reset_fifo(chip);
 
         /* Set stereo/mono */
@@ -621,7 +608,7 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
                          (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |
                          (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));
 
-        /* Set DMA controler */
+        /* Set DMA controller */
         snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
 
        return 0;
@@ -663,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma1_size = size;
-
        snd_es18xx_reset_fifo(chip);
 
         /* Set stereo/mono */
@@ -687,7 +672,7 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
                          (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |
                          (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));
 
-        /* Set DMA controler */
+        /* Set DMA controller */
         snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
 
        return 0;
@@ -752,9 +737,10 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream,
                return snd_es18xx_playback2_trigger(chip, substream, cmd);
 }
 
-static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
 {
-       struct snd_es18xx *chip = dev_id;
+       struct snd_card *card = dev_id;
+       struct snd_es18xx *chip = card->private_data;
        unsigned char status;
 
        if (chip->caps & ES18XX_CONTROL) {
@@ -797,19 +783,23 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r
 
        /* MPU */
        if ((status & MPU_IRQ) && chip->rmidi)
-               snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+               snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
 
        /* Hardware volume */
        if (status & HWV_IRQ) {
                int split = 0;
                if (chip->caps & ES18XX_HWV) {
                        split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->hw_switch->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->hw_volume->id);
                }
                if (!split) {
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_switch->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_volume->id);
                }
                /* ack interrupt */
                snd_es18xx_mixer_write(chip, 0x66, 0x00);
@@ -820,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r
 static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream)
 {
         struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        int pos;
 
        if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
                if (!(chip->active & DAC2))
                        return 0;
-               pos = snd_dma_pointer(chip->dma2, chip->dma2_size);
+               pos = snd_dma_pointer(chip->dma2, size);
                return pos >> chip->dma2_shift;
        } else {
                if (!(chip->active & DAC1))
                        return 0;
-               pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+               pos = snd_dma_pointer(chip->dma1, size);
                return pos >> chip->dma1_shift;
        }
 }
@@ -838,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s
 static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream)
 {
         struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        int pos;
 
         if (!(chip->active & ADC1))
                 return 0;
-       pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+       pos = snd_dma_pointer(chip->dma1, size);
        return pos >> chip->dma1_shift;
 }
 
@@ -973,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
 
 static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts4Source[4] = {
-               "Mic", "CD", "Line", "Master"
-       };
        static char *texts5Source[5] = {
                "Mic", "CD", "Line", "Master", "Mix"
        };
@@ -993,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
                uinfo->value.enumerated.items = 4;
                if (uinfo->value.enumerated.item > 3)
                        uinfo->value.enumerated.item = 3;
-               strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
+               strcpy(uinfo->value.enumerated.name,
+                       texts5Source[uinfo->value.enumerated.item]);
                break;
        case 0x1887:
        case 0x1888:
@@ -1069,14 +1059,7 @@ static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
        return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal;
 }
 
-static int snd_es18xx_info_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
+#define snd_es18xx_info_spatializer_enable     snd_ctl_boolean_mono_info
 
 static int snd_es18xx_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
@@ -1118,14 +1101,7 @@ static int snd_es18xx_get_hw_volume(struct snd_kcontrol *kcontrol, struct snd_ct
        return 0;
 }
 
-static int snd_es18xx_info_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
+#define snd_es18xx_info_hw_switch      snd_ctl_boolean_stereo_info
 
 static int snd_es18xx_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
@@ -1326,7 +1302,7 @@ ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
  * The chipset specific mixer controls
  */
 static struct snd_kcontrol_new snd_es18xx_opt_speaker =
-       ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0);
+       ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
 
 static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
 ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
@@ -1391,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
 static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
 {
        int data;
-       unsigned long flags;
-        spin_lock_irqsave(&chip->ctrl_lock, flags);
+
        outb(reg, chip->ctrl_port);
        data = inb(chip->ctrl_port + 1);
-        spin_unlock_irqrestore(&chip->ctrl_lock, flags);
        return data;
 }
 
@@ -1411,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
 #endif
 }
 
-static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip,
+                                          unsigned long mpu_port,
+                                          unsigned long fm_port)
 {
        int mask = 0;
 
@@ -1425,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
        if (chip->caps & ES18XX_CONTROL) {
                /* Hardware volume IRQ */
                snd_es18xx_config_write(chip, 0x27, chip->irq);
-               if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
+               if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
                        /* FM I/O */
-                       snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
-                       snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
+                       snd_es18xx_config_write(chip, 0x62, fm_port >> 8);
+                       snd_es18xx_config_write(chip, 0x63, fm_port & 0xff);
                }
-               if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+               if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
                        /* MPU-401 I/O */
-                       snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
-                       snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
+                       snd_es18xx_config_write(chip, 0x64, mpu_port >> 8);
+                       snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff);
                        /* MPU-401 IRQ */
                        snd_es18xx_config_write(chip, 0x28, chip->irq);
                }
@@ -1454,6 +1430,8 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
                snd_es18xx_write(chip, 0xB2, 0x50);
                /* Enable MPU and hardware volume interrupt */
                snd_es18xx_mixer_write(chip, 0x64, 0x42);
+               /* Enable ESS wavetable input */
+               snd_es18xx_mixer_bits(chip, 0x48, 0x10, 0x10);
        }
        else {
                int irqmask, dma1mask, dma2mask;
@@ -1518,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
                snd_es18xx_mixer_write(chip, 0x7A, 0x68);
                /* Enable and set hardware volume interrupt */
                snd_es18xx_mixer_write(chip, 0x64, 0x06);
-               if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+               if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
                        /* MPU401 share irq with audio
                           Joystick enabled
                           FM enabled */
-                       snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1);
+                       snd_es18xx_mixer_write(chip, 0x40,
+                                              0x43 | (mpu_port & 0xf0) >> 1);
                }
                snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01);
        }
@@ -1640,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
        return 0;
 }
 
-static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_probe(struct snd_es18xx *chip,
+                                       unsigned long mpu_port,
+                                       unsigned long fm_port)
 {
        if (snd_es18xx_identify(chip) < 0) {
                snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
@@ -1661,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
                chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
                break;
        case 0x1887:
-               chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
-               break;
        case 0x1888:
                chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
                break;
@@ -1677,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
        if (chip->dma1 == chip->dma2)
                chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
 
-        return snd_es18xx_initialize(chip);
+       return snd_es18xx_initialize(chip, mpu_port, fm_port);
 }
 
 static struct snd_pcm_ops snd_es18xx_playback_ops = {
@@ -1702,8 +1681,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
        .pointer =      snd_es18xx_capture_pointer,
 };
 
-static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_es18xx_pcm(struct snd_card *card, int device,
+                                   struct snd_pcm **rpcm)
 {
+       struct snd_es18xx *chip = card->private_data;
         struct snd_pcm *pcm;
        char str[16];
        int err;
@@ -1712,9 +1693,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
                *rpcm = NULL;
        sprintf(str, "ES%x", chip->version);
        if (chip->caps & ES18XX_PCM2)
-               err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm);
+               err = snd_pcm_new(card, str, device, 2, 1, &pcm);
        else
-               err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm);
+               err = snd_pcm_new(card, str, device, 1, 1, &pcm);
         if (err < 0)
                 return err;
 
@@ -1745,10 +1726,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
 #ifdef CONFIG_PM
 static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip = acard->chip;
+       struct snd_es18xx *chip = card->private_data;
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 
        snd_pcm_suspend_all(chip->pcm);
 
@@ -1763,24 +1743,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
 
 static int snd_es18xx_resume(struct snd_card *card)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip = acard->chip;
+       struct snd_es18xx *chip = card->private_data;
 
        /* restore PM register, we won't wake till (not 0x07) i/o activity though */
        snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM);
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
 #endif /* CONFIG_PM */
 
-static int snd_es18xx_free(struct snd_es18xx *chip)
+static int snd_es18xx_free(struct snd_card *card)
 {
+       struct snd_es18xx *chip = card->private_data;
+
        release_and_free_resource(chip->res_port);
        release_and_free_resource(chip->res_ctrl_port);
        release_and_free_resource(chip->res_mpu_port);
        if (chip->irq >= 0)
-               free_irq(chip->irq, (void *) chip);
+               free_irq(chip->irq, (void *) card);
        if (chip->dma1 >= 0) {
                disable_dma(chip->dma1);
                free_dma(chip->dma1);
@@ -1789,93 +1770,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip)
                disable_dma(chip->dma2);
                free_dma(chip->dma2);
        }
-       kfree(chip);
        return 0;
 }
 
 static int snd_es18xx_dev_free(struct snd_device *device)
 {
-       struct snd_es18xx *chip = device->device_data;
-       return snd_es18xx_free(chip);
+       return snd_es18xx_free(device->card);
 }
 
 static int __devinit snd_es18xx_new_device(struct snd_card *card,
                                           unsigned long port,
                                           unsigned long mpu_port,
                                           unsigned long fm_port,
-                                          int irq, int dma1, int dma2,
-                                          struct snd_es18xx ** rchip)
+                                          int irq, int dma1, int dma2)
 {
-        struct snd_es18xx *chip;
+       struct snd_es18xx *chip = card->private_data;
        static struct snd_device_ops ops = {
                .dev_free =     snd_es18xx_dev_free,
         };
        int err;
 
-       *rchip = NULL;
-        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
        spin_lock_init(&chip->reg_lock);
        spin_lock_init(&chip->mixer_lock);
-       spin_lock_init(&chip->ctrl_lock);
-        chip->card = card;
         chip->port = port;
-        chip->mpu_port = mpu_port;
-        chip->fm_port = fm_port;
         chip->irq = -1;
         chip->dma1 = -1;
         chip->dma2 = -1;
         chip->audio2_vol = 0x00;
        chip->active = 0;
 
-       if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) {
-               snd_es18xx_free(chip);
+       chip->res_port = request_region(port, 16, "ES18xx");
+       if (chip->res_port == NULL) {
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1);
                return -EBUSY;
        }
 
-       if (request_irq(irq, snd_es18xx_interrupt, SA_INTERRUPT, "ES18xx", (void *) chip)) {
-               snd_es18xx_free(chip);
+       if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx",
+                       (void *) card)) {
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq);
                return -EBUSY;
        }
        chip->irq = irq;
 
        if (request_dma(dma1, "ES18xx DMA 1")) {
-               snd_es18xx_free(chip);
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1);
                return -EBUSY;
        }
        chip->dma1 = dma1;
 
        if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
-               snd_es18xx_free(chip);
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
                return -EBUSY;
        }
        chip->dma2 = dma2;
 
-        if (snd_es18xx_probe(chip) < 0) {
-                snd_es18xx_free(chip);
-                return -ENODEV;
-        }
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-               snd_es18xx_free(chip);
+       if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
+               snd_es18xx_free(card);
+               return -ENODEV;
+       }
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_es18xx_free(card);
                return err;
        }
-        *rchip = chip;
         return 0;
 }
 
-static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_mixer(struct snd_card *card)
 {
-       struct snd_card *card;
+       struct snd_es18xx *chip = card->private_data;
        int err;
        unsigned int idx;
 
-       card = chip->card;
-
        strcpy(card->mixername, chip->pcm->name);
 
        for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) {
@@ -1997,7 +1967,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;        /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260,0x280 */
 #ifndef CONFIG_PNP
@@ -2033,10 +2003,55 @@ MODULE_PARM_DESC(dma1, "DMA 1 # for ES18xx driver.");
 module_param_array(dma2, int, NULL, 0444);
 MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");
 
-static struct platform_device *platform_devices[SNDRV_CARDS];
-
 #ifdef CONFIG_PNP
+static int isa_registered;
 static int pnp_registered;
+static int pnpc_registered;
+
+static struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
+       { .id = "ESS1869" },
+       { .id = "ESS1879" },
+       { .id = "" }            /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
+
+/* PnP main device initialization */
+static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
+{
+       if (pnp_activate_dev(pdev) < 0) {
+               snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
+               return -EBUSY;
+       }
+       /* ok. hack using Vendor-Defined Card-Level registers */
+       /* skip csn and logdev initialization - already done in isapnp_configure */
+       if (pnp_device_is_isapnp(pdev)) {
+               isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
+               isapnp_write_byte(0x27, pnp_irq(pdev, 0));      /* Hardware Volume IRQ Number */
+               if (mpu_port[dev] != SNDRV_AUTO_PORT)
+                       isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
+               isapnp_write_byte(0x72, pnp_irq(pdev, 0));      /* second IRQ */
+               isapnp_cfg_end();
+       }
+       port[dev] = pnp_port_start(pdev, 0);
+       fm_port[dev] = pnp_port_start(pdev, 1);
+       mpu_port[dev] = pnp_port_start(pdev, 2);
+       dma1[dev] = pnp_dma(pdev, 0);
+       dma2[dev] = pnp_dma(pdev, 1);
+       irq[dev] = pnp_irq(pdev, 0);
+       snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
+       snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
+       return 0;
+}
+
+static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip,
+                                       struct pnp_dev *pdev)
+{
+       chip->dev = pdev;
+       if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
+               return -EBUSY;
+       return 0;
+}
 
 static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
        /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */
@@ -2059,79 +2074,28 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
 
 MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
 
-static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
+static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
                                        struct pnp_card_link *card,
                                        const struct pnp_card_device_id *id)
 {
-       struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
-       int err;
-
-       if (!cfg)
-               return -ENOMEM;
-       acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+       if (chip->dev == NULL)
                return -EBUSY;
-       }
-       acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (acard->devc == NULL) {
-               kfree(cfg);
+
+       chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
+       if (chip->devc == NULL)
                return -EBUSY;
-       }
+
        /* Control port initialization */
-       err = pnp_activate_dev(acard->devc);
-       if (err < 0) {
+       if (pnp_activate_dev(chip->devc) < 0) {
                snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
-               kfree(cfg);
                return -EAGAIN;
        }
-       snd_printdd("pnp: port=0x%lx\n", pnp_port_start(acard->devc, 0));
-       /* PnP initialization */
-       pdev = acard->dev;
-       pnp_init_resource_table(cfg);
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (mpu_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
-               snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
-               kfree(cfg);
+       snd_printdd("pnp: port=0x%llx\n",
+                       (unsigned long long)pnp_port_start(chip->devc, 0));
+       if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
                return -EBUSY;
-       }
-       /* ok. hack using Vendor-Defined Card-Level registers */
-       /* skip csn and logdev initialization - already done in isapnp_configure */
-       if (pnp_device_is_isapnp(pdev)) {
-               isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
-               isapnp_write_byte(0x27, pnp_irq(pdev, 0));      /* Hardware Volume IRQ Number */
-               if (mpu_port[dev] != SNDRV_AUTO_PORT)
-                       isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
-               isapnp_write_byte(0x72, pnp_irq(pdev, 0));      /* second IRQ */
-               isapnp_cfg_end();
-       } else {
-               snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n");
-       }
-       port[dev] = pnp_port_start(pdev, 0);
-       fm_port[dev] = pnp_port_start(pdev, 1);
-       mpu_port[dev] = pnp_port_start(pdev, 2);
-       dma1[dev] = pnp_dma(pdev, 0);
-       dma2[dev] = pnp_dma(pdev, 1);
-       irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
-       snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
-       kfree(cfg);
+
        return 0;
 }
 #endif /* CONFIG_PNP */
@@ -2142,27 +2106,23 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
 #define is_isapnp_selected(dev)                0
 #endif
 
-static struct snd_card *snd_es18xx_card_new(int dev)
+static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
 {
-       return snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_audiodrive));
+       return snd_card_create(index[dev], id[dev], THIS_MODULE,
+                              sizeof(struct snd_es18xx), cardp);
 }
 
 static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip;
+       struct snd_es18xx *chip = card->private_data;
        struct snd_opl3 *opl3;
        int err;
 
-       if ((err = snd_es18xx_new_device(card,
-                                        port[dev],
-                                        mpu_port[dev],
-                                        fm_port[dev],
-                                        irq[dev], dma1[dev], dma2[dev],
-                                        &chip)) < 0)
+       err = snd_es18xx_new_device(card,
+                                   port[dev], mpu_port[dev], fm_port[dev],
+                                   irq[dev], dma1[dev], dma2[dev]);
+       if (err < 0)
                return err;
-       acard->chip = chip;
 
        sprintf(card->driver, "ES%x", chip->version);
        
@@ -2178,52 +2138,62 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
                        chip->port,
                        irq[dev], dma1[dev]);
 
-       if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0)
+       err = snd_es18xx_pcm(card, 0, NULL);
+       if (err < 0)
                return err;
 
-       if ((err = snd_es18xx_mixer(chip)) < 0)
+       err = snd_es18xx_mixer(card);
+       if (err < 0)
                return err;
 
        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
-               if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
-                       snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
+               if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+                                   OPL3_HW_OPL3, 0, &opl3) < 0) {
+                       snd_printk(KERN_WARNING PFX
+                                  "opl3 not detected at 0x%lx\n",
+                                  fm_port[dev]);
                } else {
-                       if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
+                       err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+                       if (err < 0)
                                return err;
                }
        }
 
        if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
-               if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
-                                              chip->mpu_port, 0,
-                                              irq[dev], 0,
-                                              &chip->rmidi)) < 0)
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
+                                         mpu_port[dev], 0,
+                                         irq[dev], 0, &chip->rmidi);
+               if (err < 0)
                        return err;
        }
 
        return snd_card_register(card);
 }
 
-static int __devinit snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int __devinit snd_es18xx_isa_match(struct device *pdev, unsigned int dev)
+{
+       return enable[dev] && !is_isapnp_selected(dev);
+}
+
+static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr)
 {
        struct snd_card *card;
        int err;
 
-       card = snd_es18xx_card_new(dev);
-       if (! card)
-               return -ENOMEM;
-       snd_card_set_dev(card, &devptr->dev);
+       err = snd_es18xx_card_new(dev, &card);
+       if (err < 0)
+               return err;
+       snd_card_set_dev(card, devptr);
        if ((err = snd_audiodrive_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
        }
-       platform_set_drvdata(devptr, card);
+       dev_set_drvdata(devptr, card);
        return 0;
 }
 
-static int __devinit snd_es18xx_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_es18xx_isa_probe(struct device *pdev, unsigned int dev)
 {
-       int dev = pdev->id;
        int err;
        static int possible_irqs[] = {5, 9, 10, 7, 11, 12, -1};
        static int possible_dmas[] = {1, 0, 3, 5, -1};
@@ -2248,13 +2218,13 @@ static int __devinit snd_es18xx_nonpnp_probe(struct platform_device *pdev)
        }
 
        if (port[dev] != SNDRV_AUTO_PORT) {
-               return snd_es18xx_nonpnp_probe1(dev, pdev);
+               return snd_es18xx_isa_probe1(dev, pdev);
        } else {
                static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280};
                int i;
                for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
                        port[dev] = possible_ports[i];
-                       err = snd_es18xx_nonpnp_probe1(dev, pdev);
+                       err = snd_es18xx_isa_probe1(dev, pdev);
                        if (! err)
                                return 0;
                }
@@ -2262,44 +2232,106 @@ static int __devinit snd_es18xx_nonpnp_probe(struct platform_device *pdev)
        }
 }
 
-static int __devexit snd_es18xx_nonpnp_remove(struct platform_device *devptr)
+static int __devexit snd_es18xx_isa_remove(struct device *devptr,
+                                          unsigned int dev)
 {
-       snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
+       snd_card_free(dev_get_drvdata(devptr));
+       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int snd_es18xx_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_es18xx_isa_suspend(struct device *dev, unsigned int n,
+                                 pm_message_t state)
 {
-       return snd_es18xx_suspend(platform_get_drvdata(dev), state);
+       return snd_es18xx_suspend(dev_get_drvdata(dev), state);
 }
 
-static int snd_es18xx_nonpnp_resume(struct platform_device *dev)
+static int snd_es18xx_isa_resume(struct device *dev, unsigned int n)
 {
-       return snd_es18xx_resume(platform_get_drvdata(dev));
+       return snd_es18xx_resume(dev_get_drvdata(dev));
 }
 #endif
 
-#define ES18XX_DRIVER  "snd_es18xx"
+#define DEV_NAME "es18xx"
 
-static struct platform_driver snd_es18xx_nonpnp_driver = {
-       .probe          = snd_es18xx_nonpnp_probe,
-       .remove         = __devexit_p(snd_es18xx_nonpnp_remove),
+static struct isa_driver snd_es18xx_isa_driver = {
+       .match          = snd_es18xx_isa_match,
+       .probe          = snd_es18xx_isa_probe,
+       .remove         = __devexit_p(snd_es18xx_isa_remove),
 #ifdef CONFIG_PM
-       .suspend        = snd_es18xx_nonpnp_suspend,
-       .resume         = snd_es18xx_nonpnp_resume,
+       .suspend        = snd_es18xx_isa_suspend,
+       .resume         = snd_es18xx_isa_resume,
 #endif
        .driver         = {
-               .name   = ES18XX_DRIVER
+               .name   = DEV_NAME
        },
 };
 
 
 #ifdef CONFIG_PNP
-static unsigned int __devinitdata es18xx_pnp_devices;
+static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
+                                           const struct pnp_device_id *id)
+{
+       static int dev;
+       int err;
+       struct snd_card *card;
+
+       if (pnp_device_is_isapnp(pdev))
+               return -ENOENT; /* we have another procedure - card */
+       for (; dev < SNDRV_CARDS; dev++) {
+               if (enable[dev] && isapnp[dev])
+                       break;
+       }
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+
+       err = snd_es18xx_card_new(dev, &card);
+       if (err < 0)
+               return err;
+       if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       snd_card_set_dev(card, &pdev->dev);
+       if ((err = snd_audiodrive_probe(card, dev)) < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       pnp_set_drvdata(pdev, card);
+       dev++;
+       return 0;
+}
 
-static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
+static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev)
+{
+       snd_card_free(pnp_get_drvdata(pdev));
+       pnp_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+       return snd_es18xx_suspend(pnp_get_drvdata(pdev), state);
+}
+static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev)
+{
+       return snd_es18xx_resume(pnp_get_drvdata(pdev));
+}
+#endif
+
+static struct pnp_driver es18xx_pnp_driver = {
+       .name = "es18xx-pnpbios",
+       .id_table = snd_audiodrive_pnpbiosids,
+       .probe = snd_audiodrive_pnp_detect,
+       .remove = __devexit_p(snd_audiodrive_pnp_remove),
+#ifdef CONFIG_PM
+       .suspend = snd_audiodrive_pnp_suspend,
+       .resume = snd_audiodrive_pnp_resume,
+#endif
+};
+
+static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
                                               const struct pnp_card_device_id *pid)
 {
        static int dev;
@@ -2313,11 +2345,11 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_es18xx_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_es18xx_card_new(dev, &card);
+       if (res < 0)
+               return res;
 
-       if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) {
+       if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
                snd_card_free(card);
                return res;
        }
@@ -2329,23 +2361,22 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
 
        pnp_set_card_drvdata(pcard, card);
        dev++;
-       es18xx_pnp_devices++;
        return 0;
 }
 
-static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard)
+static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard)
 {
        snd_card_free(pnp_get_card_drvdata(pcard));
        pnp_set_card_drvdata(pcard, NULL);
 }
 
 #ifdef CONFIG_PM
-static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
+static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
 {
        return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state);
 }
 
-static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard)
+static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard)
 {
        return snd_es18xx_resume(pnp_get_card_drvdata(pcard));
 }
@@ -2356,72 +2387,48 @@ static struct pnp_card_driver es18xx_pnpc_driver = {
        .flags = PNP_DRIVER_RES_DISABLE,
        .name = "es18xx",
        .id_table = snd_audiodrive_pnpids,
-       .probe = snd_audiodrive_pnp_detect,
-       .remove = __devexit_p(snd_audiodrive_pnp_remove),
+       .probe = snd_audiodrive_pnpc_detect,
+       .remove = __devexit_p(snd_audiodrive_pnpc_remove),
 #ifdef CONFIG_PM
-       .suspend        = snd_audiodrive_pnp_suspend,
-       .resume         = snd_audiodrive_pnp_resume,
+       .suspend        = snd_audiodrive_pnpc_suspend,
+       .resume         = snd_audiodrive_pnpc_resume,
 #endif
 };
 #endif /* CONFIG_PNP */
 
-static void __init_or_module snd_es18xx_unregister_all(void)
-{
-       int i;
-
-#ifdef CONFIG_PNP
-       if (pnp_registered)
-               pnp_unregister_card_driver(&es18xx_pnpc_driver);
-#endif
-       for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
-               platform_device_unregister(platform_devices[i]);
-       platform_driver_unregister(&snd_es18xx_nonpnp_driver);
-}
-
 static int __init alsa_card_es18xx_init(void)
 {
-       int i, err, cards = 0;
+       int err;
 
-       if ((err = platform_driver_register(&snd_es18xx_nonpnp_driver)) < 0)
-               return err;
+       err = isa_register_driver(&snd_es18xx_isa_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+       if (!err)
+               isa_registered = 1;
 
-       for (i = 0; i < SNDRV_CARDS; i++) {
-               struct platform_device *device;
-               if (! enable[i] || is_isapnp_selected(i))
-                       continue;
-               device = platform_device_register_simple(ES18XX_DRIVER,
-                                                        i, NULL, 0);
-               if (IS_ERR(device))
-                       continue;
-               if (!platform_get_drvdata(device)) {
-                       platform_device_unregister(device);
-                       continue;
-               }
-               platform_devices[i] = device;
-               cards++;
-       }
+       err = pnp_register_driver(&es18xx_pnp_driver);
+       if (!err)
+               pnp_registered = 1;
 
-#ifdef CONFIG_PNP
        err = pnp_register_card_driver(&es18xx_pnpc_driver);
-       if (!err) {
-               pnp_registered = 1;
-               cards += es18xx_pnp_devices;
-       }
-#endif
+       if (!err)
+               pnpc_registered = 1;
 
-       if(!cards) {
-#ifdef MODULE
-               snd_printk(KERN_ERR "ESS AudioDrive ES18xx soundcard not found or device busy\n");
+       if (isa_registered || pnp_registered)
+               err = 0;
 #endif
-               snd_es18xx_unregister_all();
-               return -ENODEV;
-       }
-       return 0;
+       return err;
 }
 
 static void __exit alsa_card_es18xx_exit(void)
 {
-       snd_es18xx_unregister_all();
+#ifdef CONFIG_PNP
+       if (pnpc_registered)
+               pnp_unregister_card_driver(&es18xx_pnpc_driver);
+       if (pnp_registered)
+               pnp_unregister_driver(&es18xx_pnp_driver);
+       if (isa_registered)
+#endif
+               isa_unregister_driver(&snd_es18xx_isa_driver);
 }
 
 module_init(alsa_card_es18xx_init)