[ALSA] opl3sa2 driver - added support for PnP BIOS devices

OPL3SA2 driver
The driver has been extended to support also PnP BIOS devices.
The detection path is:

1) detect PnP BIOS devices
2) detect ISA PnP devices

Signed-off-by: Jaroslav Kysela <perex@suse.cz>
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 95c7b3e..c4ebf57 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -145,6 +145,14 @@
 
 #ifdef CONFIG_PNP
 
+static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = {
+	{ .id = "YMF0021" },
+	{ .id = "NMX2210" },	/* Gateway Solo 2500 */
+	{ .id = "" }		/* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_opl3sa2_pnpbiosids);
+
 static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
 	/* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
 	{ .id = "YMH0020", .devs = { { "YMH0021" } } },
@@ -568,20 +576,18 @@
 
 #ifdef CONFIG_PNP
 static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
-				  struct pnp_card_link *card,
-				  const struct pnp_card_device_id *id)
+				  struct pnp_dev *pdev,
+				  int isapnp)
 {
-	struct pnp_dev *pdev;
-	struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+	struct pnp_resource_table * cfg;
 	int err;
 
+	if (!isapnp && pnp_device_is_isapnp(pdev))
+		return -ENOENT;	/* we have another procedure - card */
+
+	cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
 	if (!cfg)
 		return -ENOMEM;
-	pdev = chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-	if (chip->dev == NULL) {
-		kfree(cfg);
-		return -EBUSY;
-	}
 	/* PnP initialization */
 	pnp_init_resource_table(cfg);
 	if (sb_port[dev] != SNDRV_AUTO_PORT)
@@ -617,13 +623,31 @@
 	dma1[dev] = pnp_dma(pdev, 0);
 	dma2[dev] = pnp_dma(pdev, 1);
 	irq[dev] = pnp_irq(pdev, 0);
-	snd_printdd("PnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
-		sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
-	snd_printdd("PnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
-		port[dev], dma1[dev], dma2[dev], irq[dev]);
+	snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
+		pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
+	snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
+		pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
 	kfree(cfg);
+	chip->dev = pdev;
 	return 0;
 }
+
+static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *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);
+
+	if (!cfg)
+		return -ENOMEM;
+	pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+	if (pdev == NULL) {
+		kfree(cfg);
+		return -EBUSY;
+	}
+	return snd_opl3sa2_pnp(dev, chip, pdev, 1);
+}
 #endif /* CONFIG_PNP */
 
 static int snd_opl3sa2_free(opl3sa2_t *chip)
@@ -645,6 +669,7 @@
 }
 
 static int __devinit snd_opl3sa2_probe(int dev,
+				       struct pnp_dev *pdev,
 				       struct pnp_card_link *pcard,
 				       const struct pnp_card_device_id *pid)
 {
@@ -695,8 +720,13 @@
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
 		goto __error;
 #ifdef CONFIG_PNP
-	if (isapnp[dev]) {
-		if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0)
+	if (pdev) {
+		if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0)
+			goto __error;
+		snd_card_set_dev(card, &pdev->dev);
+	}
+	if (pcard) {
+		if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0)
 			goto __error;
 		snd_card_set_dev(card, &pcard->card->dev);
 	}
@@ -768,7 +798,9 @@
 	if ((err = snd_card_register(card)) < 0)
 		goto __error;
 
-	if (pcard)
+	if (pdev)
+		pnp_set_drvdata(pdev, card);
+	else if (pcard)
 		pnp_set_card_drvdata(pcard, card);
 	else
 		snd_opl3sa2_legacy[dev] = card;
@@ -780,8 +812,8 @@
 }
 
 #ifdef CONFIG_PNP
-static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
-					    const struct pnp_card_device_id *id)
+static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
+					    const struct pnp_device_id *id)
 {
         static int dev;
         int res;
@@ -789,7 +821,7 @@
         for ( ; dev < SNDRV_CARDS; dev++) {
                 if (!enable[dev] || !isapnp[dev])
                         continue;
-                res = snd_opl3sa2_probe(dev, card, id);
+                res = snd_opl3sa2_probe(dev, pdev, NULL, NULL);
                 if (res < 0)
                         return res;
                 dev++;
@@ -798,7 +830,40 @@
         return -ENODEV;
 }
 
-static void __devexit snd_opl3sa2_pnp_remove(struct pnp_card_link * pcard)
+static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
+{
+	snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev);
+        
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+}
+
+static struct pnp_driver opl3sa2_pnp_driver = {
+	.name = "opl3sa2",
+	.id_table = snd_opl3sa2_pnpbiosids,
+	.probe = snd_opl3sa2_pnp_detect,
+	.remove = __devexit_p(snd_opl3sa2_pnp_remove),
+};
+
+static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card,
+					     const struct pnp_card_device_id *id)
+{
+        static int dev;
+        int res;
+
+        for ( ; dev < SNDRV_CARDS; dev++) {
+                if (!enable[dev] || !isapnp[dev])
+                        continue;
+                res = snd_opl3sa2_probe(dev, NULL, card, id);
+                if (res < 0)
+                        return res;
+                dev++;
+                return 0;
+        }
+        return -ENODEV;
+}
+
+static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
 {
 	snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
         
@@ -810,8 +875,8 @@
 	.flags = PNP_DRIVER_RES_DISABLE,
 	.name = "opl3sa2",
 	.id_table = snd_opl3sa2_pnpids,
-	.probe = snd_opl3sa2_pnp_detect,
-	.remove = __devexit_p(snd_opl3sa2_pnp_remove),
+	.probe = snd_opl3sa2_pnp_cdetect,
+	.remove = __devexit_p(snd_opl3sa2_pnp_cremove),
 };
 #endif /* CONFIG_PNP */
 
@@ -826,10 +891,11 @@
 		if (isapnp[dev])
 			continue;
 #endif
-		if (snd_opl3sa2_probe(dev, NULL, NULL) >= 0)
+		if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0)
 			cards++;
 	}
 #ifdef CONFIG_PNP
+	cards += pnp_register_driver(&opl3sa2_pnp_driver);
 	cards += pnp_register_card_driver(&opl3sa2_pnpc_driver);
 #endif
 	if (!cards) {