Skip to contentSkip to conversation

[2.5.58][PnP] Some small points.

PATCH Ruslan U. Zakirov 4 participants 6 messages Jan 15, 2003 – Jan 21, 2003 Sound

lore
Share & tools
lore
#0 lore raw

Hello All.
1) __pnp_remove_device(dev) call twice. First time in pnpc_remove_device(dev). I think it's wrong.

pnp/card.c 2003-01-15 13:52:16.000000000 +0300 renamed from pnp/card.c~ 2003-01-15 13:52:08.000000000 +0300 +0 -1
@@ -144,7 +144,6 @@
        list_for_each_safe(pos,temp,&card->devices){
                struct pnp_dev *dev = card_to_pnp_dev(pos);
                pnpc_remove_device(dev);
-               __pnp_remove_device(dev);
        }
 }
 

_______________________________
2) We've forgot to unreg driver on module unload in opl3sa2 driver.

isa/opl3sa2.c 2003-01-15 17:47:00.000000000 +0300 renamed from isa/opl3sa2.c~ 2003-01-15 17:45:25.000000000 +0300 +3 -0
@@ -881,6 +881,9 @@
 
        for (idx = 0; idx < SNDRV_CARDS; idx++)
                snd_card_free(snd_opl3sa2_cards[idx]);
+#ifdef CONFIG_PNP
+       pnpc_unregister_driver(&opl3sa2_pnpc_driver);
+#endif
 }
 
 module_init(alsa_card_opl3sa2_init)

_________________________________
3) Queston: Why we do free in this way?
static int snd_opl3sa2_free(opl3sa2_t *chip)
{

#ifdef CONFIG_PNP
        chip->dev = NULL;   -> Here. Why NULL? Who realy free resources and how?
#endif
#ifdef CONFIG_PM
        if (chip->pm_dev)
                pm_unregister(chip->pm_dev);
#endif
        if (chip->irq >= 0)
                free_irq(chip->irq, (void *)chip);
        if (chip->res_port) {
                release_resource(chip->res_port);
                kfree_nocheck(chip->res_port);
        }
        snd_magic_kfree(chip);
        return 0;
}

_______________________________________
4) Have we got ALSA driver that work absolutly and use PnP layer in right ways?
Best regards. Ruslan.

#1 lore raw

Hi Ruslan,

Thanks for pointing these out. I appreciate your help.

Quoted 4 lines · Ruslan U. Zakirov

Hello All.
1) __pnp_remove_device(dev) call twice. First time in pnpc_remove_device(dev). I think it's wrong.

Agreed, I'll apply your patch here.

isa/opl3sa2.c 2003-01-15 17:47:00.000000000 +0300 line 888

Quoted 13 lines

_______________________________
2) We've forgot to unreg driver on module unload in opl3sa2 driver.

isa/opl3sa2.c 2003-01-15 17:47:00.000000000 +0300 renamed from isa/opl3sa2.c~ 2003-01-15 17:45:25.000000000 +0300 +3 -0
@@ -881,6 +881,9 @@
 
        for (idx = 0; idx < SNDRV_CARDS; idx++)
                snd_card_free(snd_opl3sa2_cards[idx]);
+#ifdef CONFIG_PNP
+       pnpc_unregister_driver(&opl3sa2_pnpc_driver);
+#endif
 }
 

Yep, it should unregister it there.

Quoted 7 lines
isa/opl3sa2.c 2003-01-15 17:47:00.000000000 +0300 renamed from isa/opl3sa2.c~ 2003-01-15 17:45:25.000000000 +0300 +0 -0
 module_init(alsa_card_opl3sa2_init)

_________________________________
3) Queston: Why we do free in this way?
static int snd_opl3sa2_free(opl3sa2_t *chip)
{

#ifdef CONFIG_PNP
        chip->dev = NULL;   -> Here. Why NULL? Who realy free resources and how?

The structure that chip->dev points to is freed by the pnp layer on the release call. Is this what you were asking or are you talking about something else?

Quoted 17 lines

#endif

#ifdef CONFIG_PM
        if (chip->pm_dev)
                pm_unregister(chip->pm_dev);
#endif
        if (chip->irq >= 0)
                free_irq(chip->irq, (void *)chip);
        if (chip->res_port) {
                release_resource(chip->res_port);
                kfree_nocheck(chip->res_port);
        }
        snd_magic_kfree(chip);
        return 0;
}
Quoted 3 lines

_______________________________________
4) Have we got ALSA driver that work absolutly and use PnP layer in right ways?

I believe Jaroslav is working on that now. Jaroslav, if you would like me to convert ALSA drivers please let me know.

Regards,
Adam

#2 lore raw
Quoted 9 lines · Adam Belay

Hi Ruslan,

Quoted 5 lines

3) Queston: Why we do free in this way?
static int snd_opl3sa2_free(opl3sa2_t *chip)
{

#ifdef CONFIG_PNP
        chip->dev = NULL;   -> Here. Why NULL? Who realy free resources and how?

The structure that chip->dev points to is freed by the pnp layer on the release call. Is this what you were asking or are you talking about something else?

I've got understood it already. Thanks.
At the begining I think that It's an driver job to free it, I've forgot that this pnp_devs registered in several lists of PnP layer.

Quoted 15 lines
Quoted 15 lines

#endif

#ifdef CONFIG_PM
        if (chip->pm_dev)
                pm_unregister(chip->pm_dev);
#endif
        if (chip->irq >= 0)
                free_irq(chip->irq, (void *)chip);
        if (chip->res_port) {
                release_resource(chip->res_port);
                kfree_nocheck(chip->res_port);
        }
        snd_magic_kfree(chip);
        return 0;
}
#3 lore raw
In reply to Adam Belay
Quoted 5 lines · Adam Belay
Quoted 2 lines

4) Have we got ALSA driver that work absolutly and use PnP layer in right ways?

I believe Jaroslav is working on that now. Jaroslav, if you would like me to convert ALSA drivers please let me know.

I'm working on it. Your converted drivers still misses one feature: force resources via module options. Two complete drivers using configuration templates follow.

Jaroslav

===== als100.c 1.7 vs edited =====

als100.c renamed from sound/isa/als100.c +102 -159
@@ -24,11 +24,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/time.h>
-#ifndef LINUX_ISAPNP_H
-#include <linux/isapnp.h>
-#define isapnp_card pci_bus
-#define isapnp_dev pci_dev
-#endif
+#include <linux/pnp.h>
 #include <sound/core.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -96,167 +92,116 @@
 MODULE_PARM_SYNTAX(dma16, SNDRV_DMA16_DESC);
 
 struct snd_card_als100 {
-#ifdef __ISAPNP__
-	struct isapnp_dev *dev;
-	struct isapnp_dev *devmpu;
-	struct isapnp_dev *devopl;
-#endif	/* __ISAPNP__ */
+	int dev_no;
+	struct pnp_dev *dev;
+	struct pnp_dev *devmpu;
+	struct pnp_dev *devopl;
 };
 
-static snd_card_t *snd_als100_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#ifdef __ISAPNP__
-static struct isapnp_card *snd_als100_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_als100_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-
-#define ISAPNP_ALS100(_va, _vb, _vc, _device, _audio, _mpu401, _opl) \
-        { \
-                ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-                devs : { ISAPNP_DEVICE_ID('@', '@', '@', _audio), \
-                         ISAPNP_DEVICE_ID('@', 'X', '@', _mpu401), \
-			 ISAPNP_DEVICE_ID('@', 'H', '@', _opl) } \
-        }
-
-static struct isapnp_card_id snd_als100_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_als100_pnpids[] __devinitdata = {
 	/* ALS100 - PRO16PNP */
-	ISAPNP_ALS100('A','L','S',0x0001,0x0001,0x0001,0x0001),
+	{ .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
 	/* ALS110 - MF1000 - Digimate 3D Sound */
-	ISAPNP_ALS100('A','L','S',0x0110,0x1001,0x1001,0x1001),
+	{ .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" }, } },
 	/* ALS120 */
-	ISAPNP_ALS100('A','L','S',0x0120,0x2001,0x2001,0x2001),
+	{ .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" }, } },
 	/* ALS200 */
-	ISAPNP_ALS100('A','L','S',0x0200,0x0020,0x0020,0x0001),
+	{ .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" }, } },
 	/* RTL3000 */
-	ISAPNP_ALS100('R','T','L',0x3000,0x2001,0x2001,0x2001),
-	{ ISAPNP_CARD_END, }
+	{ .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" }, } },
+	{ .id = "", } /* end */
 };
 
-ISAPNP_CARD_TABLE(snd_als100_pnpids);
-
-#endif	/* __ISAPNP__ */
+MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
 
 #define DRIVER_NAME	"snd-card-als100"
 
 
-#ifdef __ISAPNP__
-static int __init snd_card_als100_isapnp(int dev, struct snd_card_als100 *acard)
+static int __devinit snd_card_als100_isapnp(int dev, struct snd_card_als100 *acard,
+					    struct pnp_card *card,
+					    const struct pnp_card_device_id *id)
 {
-	const struct isapnp_card_id *id = snd_als100_isapnp_id[dev];
-	struct isapnp_card *card = snd_als100_isapnp_cards[dev];
-	struct isapnp_dev *pdev;
-
-	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
-	if (acard->dev->active) {
-		acard->dev = NULL;
-		return -EBUSY;
-	}
-	acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
-	if (acard->devmpu->active) {
-		acard->dev = acard->devmpu = NULL;
-		return -EBUSY;
-	}
-	acard->devopl = isapnp_find_dev(card, id->devs[2].vendor, id->devs[2].function, NULL);
-	if (acard->devopl->active) {
-		acard->dev = acard->devmpu = acard->devopl = NULL;
-		return -EBUSY;
-	}
+	struct pnp_dev *pdev;
+	struct pnp_res_cfg cfg;
+	int err;
+
+	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+	if (acard->dev == NULL)
+		return -ENODEV;
+	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
+	acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->devmpu);
 
 	pdev = acard->dev;
-	if (pdev->prepare(pdev)<0)
-		return -EAGAIN;
-
+	if (pnp_init_res_cfg(&cfg) < 0)
+		return -ENOMEM;
+	/* override resources */
 	if (port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], port[dev], 16);
+		pnp_resource_change(&cfg.io_resource[0], port[dev], 16);
 	if (dma8[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[0], dma8[dev],
-			1);
+		pnp_resource_change(&cfg.dma_resource[0], dma8[dev], 1);
 	if (dma16[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[1], dma16[dev],
-			1);
+		pnp_resource_change(&cfg.dma_resource[1], dma16[dev], 1);
 	if (irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], irq[dev], 1);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "AUDIO isapnp configure failure\n");
-		return -EBUSY;
-	}
-
-	port[dev] = pdev->resource[0].start;
-	dma8[dev] = pdev->dma_resource[1].start;
-	dma16[dev] = pdev->dma_resource[0].start;
-	irq[dev] = pdev->irq_resource[0].start;
+		pnp_resource_change(&cfg.irq_resource[0], irq[dev], 1);
+	err = pnp_activate_dev(pdev, &cfg);
+	if (err < 0) {
+		printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+		return err;
+	}
+	port[dev] = pnp_port_start(pdev, 0);
+	dma8[dev] = pnp_dma(pdev, 1);
+	dma16[dev] = pnp_dma(pdev, 0);
+	irq[dev] = pnp_irq(pdev, 0);
 
 	pdev = acard->devmpu;
-	if (pdev == NULL || pdev->prepare(pdev)<0) {
-		mpu_port[dev] = -1;
-		return 0;
-	}
-
-	if (mpu_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], mpu_port[dev],
-			2);
-	if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], mpu_irq[dev],
-			1);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n");
-		mpu_port[dev] = -1;
-		acard->devmpu = NULL;
+	if (pdev != NULL) {
+		if (pnp_init_res_cfg(&cfg) < 0)
+			goto __mpu_error;
+		if (mpu_port[dev] != SNDRV_AUTO_PORT)
+			pnp_resource_change(&cfg.io_resource[0], mpu_port[dev], 2);
+		if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
+			pnp_resource_change(&cfg.irq_resource[0], mpu_irq[dev], 1);
+		err = pnp_activate_dev(pdev, &cfg);
+		if (err < 0)
+			goto __mpu_error;
+		mpu_port[dev] = pnp_port_start(pdev, 0);
+		mpu_irq[dev] = pnp_irq(pdev, 0);
 	} else {
-		mpu_port[dev] = pdev->resource[0].start;
-		mpu_irq[dev] = pdev->irq_resource[0].start;
+	     __mpu_error:
+	     	if (pdev) {
+		     	pnp_release_card_device(pdev);
+	     		printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
+	     	}
+	     	acard->devmpu = NULL;
+	     	mpu_port[dev] = -1;
 	}
 
 	pdev = acard->devopl;
-	if (pdev == NULL || pdev->prepare(pdev)<0) {
-		fm_port[dev] = -1;
-		return 0;
-	}
-
-	if (fm_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], fm_port[dev], 4);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "OPL isapnp configure failure\n");
-		fm_port[dev] = -1;
-		acard->devopl = NULL;
+	if (pdev != NULL) {
+		if (pnp_init_res_cfg(&cfg) < 0)
+			goto __fm_error;
+		if (fm_port[dev] != SNDRV_AUTO_PORT)
+			pnp_resource_change(&cfg.io_resource[0], fm_port[dev], 4);
+		err = pnp_activate_dev(pdev, &cfg);
+		if (err < 0)
+			goto __fm_error;
+		fm_port[dev] = pnp_port_start(pdev, 0);
 	} else {
-		fm_port[dev] = pdev->resource[0].start;
+	      __fm_error:
+	     	if (pdev) {
+		     	pnp_release_card_device(pdev);
+	     		printk(KERN_ERR PFX "OPL3 pnp configure failure, skipping\n");
+	     	}
+	     	acard->devopl = NULL;
+	     	fm_port[dev] = -1;
 	}
 
 	return 0;
 }
 
-static void snd_card_als100_deactivate(struct snd_card_als100 *acard)
-{
-	if (acard->dev) {
-		acard->dev->deactivate(acard->dev);
-		acard->dev = NULL;
-	}
-	if (acard->devmpu) {
-		acard->devmpu->deactivate(acard->devmpu);
-		acard->devmpu = NULL;
-	}
-	if (acard->devopl) {
-		acard->devopl->deactivate(acard->devopl);
-		acard->devopl = NULL;
-	}
-}
-#endif	/* __ISAPNP__ */
-
-static void snd_card_als100_free(snd_card_t *card)
-{
-	struct snd_card_als100 *acard = (struct snd_card_als100 *)card->private_data;
-
-	if (acard) {
-#ifdef __ISAPNP__
-		snd_card_als100_deactivate(acard);
-#endif	/* __ISAPNP__ */
-	}
-}
-
-static int __init snd_card_als100_probe(int dev)
+static int __init snd_card_als100_probe(int dev,
+					struct pnp_card *pcard,
+					const struct pnp_card_device_id *pid)
 {
 	int error;
 	sb_t *chip;
@@ -268,18 +213,11 @@
 				 sizeof(struct snd_card_als100))) == NULL)
 		return -ENOMEM;
 	acard = (struct snd_card_als100 *)card->private_data;
-	card->private_free = snd_card_als100_free;
 
-#ifdef __ISAPNP__
-	if ((error = snd_card_als100_isapnp(dev, acard))) {
+	if ((error = snd_card_als100_isapnp(dev, acard, pcard, pid))) {
 		snd_card_free(card);
 		return error;
 	}
-#else
-	printk(KERN_ERR PFX "you have to enable PnP support ...\n");
-	snd_card_free(card);
-	return -ENOSYS;
-#endif	/* __ISAPNP__ */
 
 	if ((error = snd_sbdsp_create(card, port[dev],
 				      irq[dev],
@@ -336,13 +274,12 @@
 		snd_card_free(card);
 		return error;
 	}
-	snd_als100_cards[dev] = card;
+	pnpc_set_drvdata(pcard, card);
 	return 0;
 }
 
-#ifdef __ISAPNP__
-static int __init snd_als100_isapnp_detect(struct isapnp_card *card,
-					   const struct isapnp_card_id *id)
+static int __devinit snd_als100_pnp_detect(struct pnp_card *card,
+					   const struct pnp_card_device_id *id)
 {
 	static int dev;
 	int res;
@@ -350,9 +287,7 @@
 	for ( ; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev])
 			continue;
-		snd_als100_isapnp_cards[dev] = card;
-		snd_als100_isapnp_id[dev] = id;
-		res = snd_card_als100_probe(dev);
+		res = snd_card_als100_probe(dev, card, id);
 		if (res < 0)
 			return res;
 		dev++;
@@ -360,17 +295,28 @@
 	}
 	return -ENODEV;
 }
-#endif
+
+static void __devexit snd_als100_pnp_remove(struct pnp_card * pcard)
+{
+	snd_card_t *card = (snd_card_t *) pnpc_get_drvdata(pcard);
+
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+}
+
+static struct pnpc_driver als100_pnpc_driver = {
+	.flags          = PNPC_DRIVER_DO_NOT_ACTIVATE,
+        .name           = "als100",
+        .id_table       = snd_als100_pnpids,
+        .probe          = snd_als100_pnp_detect,
+        .remove         = __devexit_p(snd_als100_pnp_remove),
+};
 
 static int __init alsa_card_als100_init(void)
 {
 	int cards = 0;
 
-#ifdef __ISAPNP__
-	cards += isapnp_probe_cards(snd_als100_pnpids, snd_als100_isapnp_detect);
-#else
-	printk(KERN_ERR PFX "you have to enable ISA PnP support.\n");
-#endif
+	cards += pnpc_register_driver(&als100_pnpc_driver);
 #ifdef MODULE
 	if (!cards)
 		printk(KERN_ERR "no ALS100 based soundcards found\n");
@@ -380,10 +326,7 @@
 
 static void __exit alsa_card_als100_exit(void)
 {
-	int dev;
-
-	for (dev = 0; dev < SNDRV_CARDS; dev++)
-		snd_card_free(snd_als100_cards[dev]);
+	pnpc_unregister_driver(&als100_pnpc_driver);
 }
 
 module_init(alsa_card_als100_init)

===== opl3sa2.c 1.14 vs edited =====

opl3sa2.c renamed from sound/isa/opl3sa2.c +76 -49

242 lines not on this page · raw message

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs

#4 lore raw
Quoted 12 lines · Jaroslav Kysela
Quoted 5 lines · Adam Belay
Quoted 2 lines

4) Have we got ALSA driver that work absolutly and use PnP layer in right ways?

I believe Jaroslav is working on that now. Jaroslav, if you would like me to convert ALSA drivers please let me know.

I'm working on it. Your converted drivers still misses one feature: force resources via module options. Two complete drivers using configuration templates follow.

[snip]

Quoted 9 lines
opl3sa2.c renamed from sound/isa/opl3sa2.c +5 -2
-static void snd_opl3sa2_isapnp_remove(struct pnp_card * card)
+static void __devexit snd_opl3sa2_isapnp_remove(struct pnp_card * pcard)
 {
-/* FIXME */
+	snd_card_t * card = (snd_card_t *) pnpc_get_drvdata(pcard);
+	
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
 }

[snip]

opl3sa2.c line 911

Quoted 11 lines

static void __exit alsa_card_opl3sa2_exit(void)
{

opl3sa2.c renamed from sound/isa/opl3sa2.c +4 -3
-	int idx;
+        int dev;
 
-	for (idx = 0; idx < SNDRV_CARDS; idx++)
-		snd_card_free(snd_opl3sa2_cards[idx]);
+	pnpc_unregister_driver(&opl3sa2_pnpc_driver);
+	for (dev = 0; dev < SNDRV_CARDS; dev++)
+		snd_card_free(snd_opl3sa2_cards[dev]);
 }

Hello Jaroslav and other.
I could be wrong.
1) It's cause an compilation error without CONFIG_PNP.
2) We can delete call of snd_card_free in module exit function, it'll be freed within driver->remove call. It's realy needed only without CONFIG_PNP_CARD.
Thanks for example of driver, I've understood some tricks from it.
Best regards, Ruslan.

#5 lore raw
Quoted 30 lines · Ruslan U. Zakirov
Quoted 12 lines · Jaroslav Kysela
Quoted 5 lines · Adam Belay
Quoted 2 lines

4) Have we got ALSA driver that work absolutly and use PnP layer in right ways?

I believe Jaroslav is working on that now. Jaroslav, if you would like me to convert ALSA drivers please let me know.

I'm working on it. Your converted drivers still misses one feature: force resources via module options. Two complete drivers using configuration templates follow.

[snip]

Quoted 9 lines
opl3sa2.c renamed from sound/isa/opl3sa2.c +5 -2
-static void snd_opl3sa2_isapnp_remove(struct pnp_card * card)
+static void __devexit snd_opl3sa2_isapnp_remove(struct pnp_card * pcard)
 {
-/* FIXME */
+	snd_card_t * card = (snd_card_t *) pnpc_get_drvdata(pcard);
+	
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
 }

[snip]

Quoted 5 lines

static void __exit alsa_card_opl3sa2_exit(void)
{

opl3sa2.c renamed from sound/isa/opl3sa2.c +1 -1
-	int idx;
+        int dev;
Quoted 9 lines

opl3sa2.c line 911

Quoted 6 lines
opl3sa2.c renamed from sound/isa/opl3sa2.c +3 -2
-	for (idx = 0; idx < SNDRV_CARDS; idx++)
-		snd_card_free(snd_opl3sa2_cards[idx]);
+	pnpc_unregister_driver(&opl3sa2_pnpc_driver);
+	for (dev = 0; dev < SNDRV_CARDS; dev++)
+		snd_card_free(snd_opl3sa2_cards[dev]);
 }

Hello Jaroslav and other.
I could be wrong.
1) It's cause an compilation error without CONFIG_PNP.

Yes, the opl3sa2_pnpc_driver structure is not defined. Corrected.

Quoted 3 lines

2) We can delete call of snd_card_free in module exit function, it'll be freed within driver->remove call. It's realy needed only without CONFIG_PNP_CARD.

No, we can mix pnp and non-pnp cards. The non-pnp cards have to be removed manually.

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs