#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
+#include <linux/pnp.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 static int dma2 = SNDRV_DEFAULT_DMA1;          /* 0,1,3 */
 static int wss;
 static int ide;
+#ifdef CONFIG_PNP
+static int isapnp = 1;                         /* Enable ISA PnP detection */
+#endif
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for miro soundcard.");
 MODULE_PARM_DESC(wss, "wss mode");
 module_param(ide, int, 0444);
 MODULE_PARM_DESC(ide, "enable ide port");
+#ifdef CONFIG_PNP
+module_param(isapnp, bool, 0444);
+MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
+#endif
 
 #define OPTi9XX_HW_DETECT      0
 #define OPTi9XX_HW_82C928      1
        "82C930", "82C931", "82C933"
 };
 
+static int snd_miro_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+
+static struct pnp_card_device_id snd_miro_pnpids[] = {
+       /* PCM20 and PCM12 in PnP mode */
+       { .id = "MIR0924",
+         .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, },
+       { .id = "" }
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids);
+
+#endif /* CONFIG_PNP */
+
 /* 
  *  ACI control
  */
        chip->mpu_port = -1;
        chip->mpu_irq = -1;
 
+       chip->pwd_reg = 3;
+
+#ifdef CONFIG_PNP
+       if (isapnp && chip->mc_base)
+               /* PnP resource gives the least 10 bits */
+               chip->mc_base |= 0xc00;
+       else
+#endif
+               chip->mc_base = 0xf8c;
+
        switch (hardware) {
        case OPTi9XX_HW_82C929:
-               chip->mc_base = 0xf8c;
                chip->password = 0xe3;
-               chip->pwd_reg = 3;
                break;
 
        case OPTi9XX_HW_82C924:
-               chip->mc_base = 0xf8c;
                chip->password = 0xe5;
-               chip->pwd_reg = 3;
                break;
 
        default:
                return -EINVAL;
        }
 
-       switch (chip->wss_base) {
-       case 0x530:
+       /* PnP resource says it decodes only 10 bits of address */
+       switch (chip->wss_base & 0x3ff) {
+       case 0x130:
+               chip->wss_base = 0x530;
                wss_base_bits = 0x00;
                break;
-       case 0x604:
+       case 0x204:
+               chip->wss_base = 0x604;
                wss_base_bits = 0x03;
                break;
-       case 0xe80:
+       case 0x280:
+               chip->wss_base = 0xe80;
                wss_base_bits = 0x01;
                break;
-       case 0xf40:
+       case 0x340:
+               chip->wss_base = 0xf40;
                wss_base_bits = 0x02;
                break;
        default:
 static void snd_card_miro_free(struct snd_card *card)
 {
        struct snd_miro *miro = card->private_data;
-        
+
        release_and_free_resource(miro->res_aci_port);
        if (miro->aci)
                miro->aci->aci_port = 0;
 
 static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n)
 {
+#ifdef CONFIG_PNP
+       if (snd_miro_pnp_is_probed)
+               return 0;
+       if (isapnp)
+               return 0;
+#endif
        return 1;
 }
 
        },
 };
 
+#ifdef CONFIG_PNP
+
+static int __devinit snd_card_miro_pnp(struct snd_miro *chip,
+                                       struct pnp_card_link *card,
+                                       const struct pnp_card_device_id *pid)
+{
+       struct pnp_dev *pdev;
+       int err;
+       struct pnp_dev *devmpu;
+       struct pnp_dev *devmc;
+
+       pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+       if (pdev == NULL)
+               return -EBUSY;
+
+       devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
+       if (devmpu == NULL)
+               return -EBUSY;
+
+       devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
+       if (devmc == NULL)
+               return -EBUSY;
+
+       err = pnp_activate_dev(pdev);
+       if (err < 0) {
+               snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
+               return err;
+       }
+
+       err = pnp_activate_dev(devmc);
+       if (err < 0) {
+               snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n",
+                                   err);
+               return err;
+       }
+
+       port = pnp_port_start(pdev, 1);
+       fm_port = pnp_port_start(pdev, 2) + 8;
+
+       /*
+        * The MC(0) is never accessed and the miroSOUND PCM20 card does not
+        * include it in the PnP resource range. OPTI93x include it.
+        */
+       chip->mc_base = pnp_port_start(devmc, 0) - 1;
+       chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
+
+       irq = pnp_irq(pdev, 0);
+       dma1 = pnp_dma(pdev, 0);
+       dma2 = pnp_dma(pdev, 1);
+
+       if (mpu_port > 0) {
+               err = pnp_activate_dev(devmpu);
+               if (err < 0) {
+                       snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
+                       mpu_port = -1;
+                       return err;
+               }
+               mpu_port = pnp_port_start(devmpu, 0);
+               mpu_irq = pnp_irq(devmpu, 0);
+       }
+       return 0;
+}
+
+static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard,
+                                       const struct pnp_card_device_id *pid)
+{
+       struct snd_card *card;
+       int err;
+       struct snd_miro *miro;
+
+       if (snd_miro_pnp_is_probed)
+               return -EBUSY;
+       if (!isapnp)
+               return -ENODEV;
+       err = snd_card_create(index, id, THIS_MODULE,
+                               sizeof(struct snd_miro), &card);
+       if (err < 0)
+               return err;
+
+       card->private_free = snd_card_miro_free;
+       miro = card->private_data;
+
+       err = snd_card_miro_pnp(miro, pcard, pid);
+       if (err) {
+               snd_card_free(card);
+               return err;
+       }
+
+       /* only miroSOUND PCM20 and PCM12 == OPTi924 */
+       err = snd_miro_init(miro, OPTi9XX_HW_82C924);
+       if (err) {
+               snd_card_free(card);
+               return err;
+       }
+
+       err = snd_miro_opti_check(miro);
+       if (err) {
+               snd_printk(KERN_ERR "OPTI chip not found\n");
+               snd_card_free(card);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pcard->card->dev);
+       err = snd_miro_probe(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       pnp_set_card_drvdata(pcard, card);
+       snd_miro_pnp_is_probed = 1;
+       return 0;
+}
+
+static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard)
+{
+       snd_card_free(pnp_get_card_drvdata(pcard));
+       pnp_set_card_drvdata(pcard, NULL);
+       snd_miro_pnp_is_probed = 0;
+}
+
+static struct pnp_card_driver miro_pnpc_driver = {
+       .flags          = PNP_DRIVER_RES_DISABLE,
+       .name           = "miro",
+       .id_table       = snd_miro_pnpids,
+       .probe          = snd_miro_pnp_probe,
+       .remove         = __devexit_p(snd_miro_pnp_remove),
+};
+#endif
+
 static int __init alsa_card_miro_init(void)
 {
+#ifdef CONFIG_PNP
+       pnp_register_card_driver(&miro_pnpc_driver);
+       if (snd_miro_pnp_is_probed)
+               return 0;
+       pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
        return isa_register_driver(&snd_miro_driver, 1);
 }
 
 static void __exit alsa_card_miro_exit(void)
 {
-       isa_unregister_driver(&snd_miro_driver);
+       if (!snd_miro_pnp_is_probed) {
+               isa_unregister_driver(&snd_miro_driver);
+               return;
+       }
+#ifdef CONFIG_PNP
+       pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
 }
 
 module_init(alsa_card_miro_init)