Re: [PATCH][2.5] ALSA ISAPNP update for sound/isa/opl3sa2.c

Zwane Mwaikambo (zwane@holomorphy.com)
Sun, 1 Dec 2002 01:36:21 -0500 (EST)


On Sat, 30 Nov 2002, Zwane Mwaikambo wrote:

> ISAPNP/ALSA hasn't been working for a while now (cards didn't get
> detected), here is a patch to update OPL3SA2 to the new PnP layer.
>
> ALSA device list:
> #0: Yamaha OPL3-SA23 at 0x100, irq 5, dma 1&3
>
> Driver tested in kernel and modular, i have tried to maintain
> detection/resource override semantics and general detection code
> paths.

Updated to fix broken module unload

Index: linux-2.5.50/sound/isa/opl3sa2.c
===================================================================
RCS file: /build/cvsroot/linux-2.5.50/sound/isa/opl3sa2.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 opl3sa2.c
--- linux-2.5.50/sound/isa/opl3sa2.c 28 Nov 2002 01:36:04 -0000 1.1.1.1
+++ linux-2.5.50/sound/isa/opl3sa2.c 1 Dec 2002 05:17:24 -0000
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/slab.h>
+#include <linux/pnp.h>
#ifndef LINUX_ISAPNP_H
#include <linux/isapnp.h>
#define isapnp_card pci_bus
@@ -135,6 +136,7 @@

typedef struct snd_opl3sa2 opl3sa2_t;
#define chip_t opl3sa2_t
+int nr_cards;

struct snd_opl3sa2 {
snd_card_t *card;
@@ -148,7 +150,7 @@
snd_rawmidi_t *rmidi;
cs4231_t *cs4231;
#ifdef __ISAPNP__
- struct isapnp_dev *dev;
+ struct pnp_dev *dev;
#endif
unsigned char ctlregs[0x20];
int ymode; /* SL added */
@@ -164,30 +166,28 @@
static snd_card_t *snd_opl3sa2_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;

#ifdef __ISAPNP__
+static struct pnp_dev *snd_opl3sa2_isapnp_devs[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;

-static struct isapnp_card *snd_opl3sa2_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_opl3sa2_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-
-#define ISAPNP_OPL3SA2(_va, _vb, _vc, _device, _function) \
- { \
- ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
- devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _function), } \
- }
-
-static struct isapnp_card_id snd_opl3sa2_pnpids[] __devinitdata = {
+/* Please try and keep the 1:1 mapping with the dev listing below */
+static const struct pnp_id pnp_opl3sa2_cards[] = {
/* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
- ISAPNP_OPL3SA2('Y','M','H',0x0020,0x0021),
+ {.id = "YMH0020", .driver_data = 0},
/* Yamaha OPL3-SA3 (integrated on Intel's Pentium II AL440LX motherboard) */
- ISAPNP_OPL3SA2('Y','M','H',0x0030,0x0021),
+ {.id = "YMH0030", .driver_data = 0},
/* Yamaha OPL3-SA2 */
- ISAPNP_OPL3SA2('Y','M','H',0x0800,0x0021),
+ {.id = "YMH0800", .driver_data = 0},
/* NeoMagic MagicWave 3DX */
- ISAPNP_OPL3SA2('N','M','X',0x2200,0x2210),
- /* --- */
- { ISAPNP_CARD_END, } /* end */
+ {.id = "NMX2200", .driver_data = 0},
+ {"", 0}
};

-ISAPNP_CARD_TABLE(snd_opl3sa2_pnpids);
+static const struct pnp_id pnp_opl3sa2_devs[] = {
+ {.id = "YMH0021", .driver_data = 0},
+ {.id = "YMH0021", .driver_data = 0},
+ {.id = "YMH0021", .driver_data = 0},
+ {.id = "NMX2210", .driver_data = 0},
+ {"", 0}
+};

#endif /* __ISAPNP__ */

@@ -246,6 +246,7 @@
unsigned long port;
unsigned char tmp, tmp1;
char str[2];
+ int ret;

card = chip->card;
port = chip->port;
@@ -256,7 +257,8 @@
tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp == 0xff) {
snd_printd("OPL3-SA [0x%lx] detect = 0x%x\n", port, tmp);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_fail;
}
switch (tmp & 0x07) {
case 0x01:
@@ -276,14 +278,16 @@
snd_opl3sa2_write(chip, OPL3SA2_MISC, tmp ^ 7);
if ((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MISC)) != tmp) {
snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_fail;
}
/* try if the MIC register is accesible */
tmp = snd_opl3sa2_read(chip, OPL3SA2_MIC);
snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a);
if (((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC)) & 0x9f) != 0x8a) {
snd_printd("OPL3-SA [0x%lx] detect (2) = 0x%x (0x%x)\n", port, tmp, tmp1);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_fail;
}
snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x9f);
/* initialization */
@@ -308,6 +312,10 @@
snd_opl3sa2_write(chip, OPL3SA3_ANLG_DOWN, 0x00); /* Analog Block Partial Power Down - default */
}
return 0;
+
+out_fail:
+ release_resource(chip->res_port);
+ return ret;
}

static void snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -634,22 +642,38 @@

#endif /* CONFIG_PM */

+static int snd_opl3sa2_free(opl3sa2_t *chip)
+{
+#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;
+}
+
+static int snd_opl3sa2_dev_free(snd_device_t *device)
+{
+ opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, device->device_data, return -ENXIO);
+ return snd_opl3sa2_free(chip);
+}
+
#ifdef __ISAPNP__
static int __init snd_opl3sa2_isapnp(int dev, opl3sa2_t *chip)
{
- const struct isapnp_card_id *id = snd_opl3sa2_isapnp_id[dev];
- struct isapnp_card *card = snd_opl3sa2_isapnp_cards[dev];
- struct isapnp_dev *pdev;
+ int res = 0;
+ struct pnp_dev *pdev = snd_opl3sa2_isapnp_devs[dev];
+
+ if (!enable[dev])
+ return -ENODEV;

- chip->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
- if (chip->dev->active) {
- chip->dev = NULL;
- return -EBUSY;
- }
- /* PnP initialization */
- pdev = chip->dev;
- if (pdev->prepare(pdev)<0)
- return -EAGAIN;
if (sb_port[dev] != SNDRV_AUTO_PORT)
isapnp_resource_change(&pdev->resource[0], sb_port[dev], 16);
if (wss_port[dev] != SNDRV_AUTO_PORT)
@@ -666,59 +690,26 @@
isapnp_resource_change(&pdev->dma_resource[1], dma2[dev], 1);
if (irq[dev] != SNDRV_AUTO_IRQ)
isapnp_resource_change(&pdev->irq_resource[0], irq[dev], 1);
- if (pdev->activate(pdev)<0) {
- snd_printk("isapnp configure failure (out of resources?)\n");
- return -EBUSY;
- }
- sb_port[dev] = pdev->resource[0].start;
- wss_port[dev] = pdev->resource[1].start;
- fm_port[dev] = pdev->resource[2].start;
- midi_port[dev] = pdev->resource[3].start;
- port[dev] = pdev->resource[4].start;
+
+ sb_port[dev] = pci_resource_start(pdev, 0);
+ wss_port[dev] = pci_resource_start(pdev, 1);
+ fm_port[dev] = pci_resource_start(pdev, 2);
+ midi_port[dev] = pci_resource_start(pdev, 3);
+ port[dev] = pci_resource_start(pdev, 4);
dma1[dev] = pdev->dma_resource[0].start;
dma2[dev] = pdev->dma_resource[1].start;
irq[dev] = pdev->irq_resource[0].start;
+
snd_printdd("isapnp 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("isapnp OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
port[dev], dma1[dev], dma2[dev], irq[dev]);
- return 0;
-}
-
-static void snd_opl3sa2_deactivate(opl3sa2_t *chip)
-{
- if (chip->dev) {
- chip->dev->deactivate(chip->dev);
- chip->dev = NULL;
- }
+ chip->dev = pdev;
+
+ return res;
}
#endif /* __ISAPNP__ */

-static int snd_opl3sa2_free(opl3sa2_t *chip)
-{
-#ifdef __ISAPNP__
- snd_opl3sa2_deactivate(chip);
-#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;
-}
-
-static int snd_opl3sa2_dev_free(snd_device_t *device)
-{
- opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, device->device_data, return -ENXIO);
- return snd_opl3sa2_free(chip);
-}
-
static int __init snd_opl3sa2_probe(int dev)
{
int xirq, xdma1, xdma2;
@@ -763,7 +754,9 @@
err = -ENOMEM;
goto __error;
}
+ spin_lock_init(&chip->reg_lock);
chip->irq = -1;
+
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
goto __error;
#ifdef __ISAPNP__
@@ -855,30 +848,47 @@
}

#ifdef __ISAPNP__
-static int __init snd_opl3sa2_isapnp_detect(struct isapnp_card *card,
- const struct isapnp_card_id *id)
+static int pnp_opl3sa2_probe(struct pnp_dev *pdev, const struct pnp_id *card_id,
+ const struct pnp_id *dev_id)
{
- static int dev;
+ static int dev;
int res;

for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev])
continue;
- snd_opl3sa2_isapnp_cards[dev] = card;
- snd_opl3sa2_isapnp_id[dev] = id;
+ snd_opl3sa2_isapnp_devs[dev] = pdev;
res = snd_opl3sa2_probe(dev);
if (res < 0)
return res;
dev++;
+ nr_cards++;
return 0;
}
return -ENODEV;
}
+
+static void pnp_opl3sa2_remove(struct pnp_dev *pdev)
+{
+ opl3sa2_t *chip = pdev->driver_data;
+ if (chip)
+ chip->dev = NULL;
+ nr_cards--;
+}
+
+static struct pnp_driver snd_opl3sa2_pnp_driver = {
+ .name = "opl3sa2",
+ .card_id_table = pnp_opl3sa2_cards,
+ .id_table = pnp_opl3sa2_devs,
+ .probe = pnp_opl3sa2_probe,
+ .remove = pnp_opl3sa2_remove,
+};
+
#endif /* __ISAPNP__ */

static int __init alsa_card_opl3sa2_init(void)
{
- int dev, cards = 0;
+ int dev;

for (dev = 0; dev < SNDRV_CARDS; dev++) {
if (!enable[dev])
@@ -888,15 +898,21 @@
continue;
#endif
if (snd_opl3sa2_probe(dev) >= 0)
- cards++;
+ nr_cards++;
}
+
#ifdef __ISAPNP__
- cards += isapnp_probe_cards(snd_opl3sa2_pnpids, snd_opl3sa2_isapnp_detect);
+ /* upon registration the probe function will increment nr_cards */
+ pnp_register_driver(&snd_opl3sa2_pnp_driver);
#endif
- if (!cards) {
+
+ if (nr_cards == 0) {
#ifdef MODULE
printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n");
#endif
+#ifdef __ISAPNP__
+ pnp_unregister_driver(&snd_opl3sa2_pnp_driver);
+#endif
return -ENODEV;
}
return 0;
@@ -905,9 +921,11 @@
static void __exit alsa_card_opl3sa2_exit(void)
{
int idx;
-
for (idx = 0; idx < SNDRV_CARDS; idx++)
snd_card_free(snd_opl3sa2_cards[idx]);
+#ifdef __ISAPNP__
+ pnp_unregister_driver(&snd_opl3sa2_pnp_driver);
+#endif
}

module_init(alsa_card_opl3sa2_init)

-- 
function.linuxpower.ca
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/