summaryrefslogtreecommitdiff
path: root/sound/isa/es1688/es1688.c
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2010-05-10 09:47:32 +0200
committerTakashi Iwai <tiwai@suse.de>2010-05-10 09:49:30 +0200
commita20971b201ac1fcd236400942c98b0106c42c70a (patch)
treef71d82b13c1b0d8a94187a68c0b694605664bbf3 /sound/isa/es1688/es1688.c
parent396fa8272601c3d488cb8391c3962a7ee552afd0 (diff)
ALSA: Merge es1688 and es968 drivers
The ESS ES968 chip is nothing more then a PnP companion for a non-PnP audio chip. It was paired with non-PnP ESS' chips: ES688 and ES1688. The ESS' audio chips are handled by the es1688 driver in native mode. The PnP cards are handled by the ES968 driver in SB compatible mode. Move the ES968 chip handling to the es1688 driver so the driver can handle both PnP and non-PnP cards. The es968 is removed. Also, a new PnP id is added for the card I acquired (the change was tested on this card). Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/isa/es1688/es1688.c')
-rw-r--r--sound/isa/es1688/es1688.c205
1 files changed, 177 insertions, 28 deletions
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 281679493fb4..fdcce311f80a 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/isa.h>
+#include <linux/isapnp.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/moduleparam.h>
@@ -45,8 +46,13 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100},"
"{ESS,ES688 AudioDrive,pnp:ESS6881},"
"{ESS,ES1688 AudioDrive,pnp:ESS1681}}");
+MODULE_ALIAS("snd_es968");
+
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+#ifdef CONFIG_PNP
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+#endif
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
@@ -60,6 +66,10 @@ MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
+#ifdef CONFIG_PNP
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
+#endif
MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
@@ -74,14 +84,21 @@ MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
module_param_array(dma8, int, NULL, 0444);
MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
+#ifdef CONFIG_PNP
+#define is_isapnp_selected(dev) isapnp[dev]
+#else
+#define is_isapnp_selected(dev) 0
+#endif
+
static int __devinit snd_es1688_match(struct device *dev, unsigned int n)
{
- return enable[n];
+ return enable[n] && !is_isapnp_selected(n);
}
static int __devinit snd_es1688_legacy_create(struct snd_card *card,
- struct snd_es1688 *chip, struct device *dev, unsigned int n)
+ struct device *dev, unsigned int n)
{
+ struct snd_es1688 *chip = card->private_data;
static long possible_ports[] = {0x220, 0x240, 0x260};
static int possible_irqs[] = {5, 9, 10, 7, -1};
static int possible_dmas[] = {1, 3, 0, -1};
@@ -117,32 +134,20 @@ static int __devinit snd_es1688_legacy_create(struct snd_card *card,
return error;
}
-static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
+static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n)
{
- struct snd_card *card;
- struct snd_es1688 *chip;
+ struct snd_es1688 *chip = card->private_data;
struct snd_opl3 *opl3;
struct snd_pcm *pcm;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE,
- sizeof(struct snd_es1688), &card);
- if (error < 0)
- return error;
-
- chip = card->private_data;
-
- error = snd_es1688_legacy_create(card, chip, dev, n);
- if (error < 0)
- goto out;
-
error = snd_es1688_pcm(card, chip, 0, &pcm);
if (error < 0)
- goto out;
+ return error;
error = snd_es1688_mixer(card, chip);
if (error < 0)
- goto out;
+ return error;
strcpy(card->driver, "ES1688");
strcpy(card->shortname, pcm->name);
@@ -155,12 +160,12 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
if (fm_port[n] > 0) {
if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
OPL3_HW_OPL3, 0, &opl3) < 0)
- dev_warn(dev,
+ dev_warn(card->dev,
"opl3 not detected at 0x%lx\n", fm_port[n]);
else {
error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (error < 0)
- goto out;
+ return error;
}
}
@@ -170,23 +175,41 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
chip->mpu_port, 0,
mpu_irq[n], IRQF_DISABLED, NULL);
if (error < 0)
- goto out;
+ return error;
}
+ return snd_card_register(card);
+}
+
+static int __devinit snd_es1688_isa_probe(struct device *dev, unsigned int n)
+{
+ struct snd_card *card;
+ int error;
+
+ error = snd_card_create(index[n], id[n], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
+ if (error < 0)
+ return error;
+
+ error = snd_es1688_legacy_create(card, dev, n);
+ if (error < 0)
+ goto out;
+
snd_card_set_dev(card, dev);
- error = snd_card_register(card);
+ error = snd_es1688_probe(card, n);
if (error < 0)
goto out;
dev_set_drvdata(dev, card);
- return 0;
-out: snd_card_free(card);
+ return 0;
+out:
+ snd_card_free(card);
return error;
}
-static int __devexit snd_es1688_remove(struct device *dev, unsigned int n)
+static int __devexit snd_es1688_isa_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
dev_set_drvdata(dev, NULL);
@@ -195,8 +218,8 @@ static int __devexit snd_es1688_remove(struct device *dev, unsigned int n)
static struct isa_driver snd_es1688_driver = {
.match = snd_es1688_match,
- .probe = snd_es1688_probe,
- .remove = __devexit_p(snd_es1688_remove),
+ .probe = snd_es1688_isa_probe,
+ .remove = __devexit_p(snd_es1688_isa_remove),
#if 0 /* FIXME */
.suspend = snd_es1688_suspend,
.resume = snd_es1688_resume,
@@ -206,14 +229,140 @@ static struct isa_driver snd_es1688_driver = {
}
};
+static int snd_es968_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+static int __devinit snd_card_es968_pnp(struct snd_card *card, unsigned int n,
+ struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ struct snd_es1688 *chip = card->private_data;
+ struct pnp_dev *pdev;
+ int error;
+
+ pdev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+ if (pdev == NULL)
+ return -ENODEV;
+
+ error = pnp_activate_dev(pdev);
+ if (error < 0) {
+ snd_printk(KERN_ERR "ES968 pnp configure failure\n");
+ return error;
+ }
+ port[n] = pnp_port_start(pdev, 0);
+ dma8[n] = pnp_dma(pdev, 0);
+ irq[n] = pnp_irq(pdev, 0);
+
+ return snd_es1688_create(card, chip, port[n], mpu_port[n], irq[n],
+ mpu_irq[n], dma8[n], ES1688_HW_AUTO);
+}
+
+static int __devinit snd_es968_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ struct snd_card *card;
+ static unsigned int dev;
+ int error;
+ struct snd_es1688 *chip;
+
+ if (snd_es968_pnp_is_probed)
+ return -EBUSY;
+ for ( ; dev < SNDRV_CARDS; dev++) {
+ if (enable[dev] && isapnp[dev])
+ break;
+ }
+
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
+ if (error < 0)
+ return error;
+ chip = card->private_data;
+
+ error = snd_card_es968_pnp(card, dev, pcard, pid);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
+ }
+ snd_card_set_dev(card, &pcard->card->dev);
+ error = snd_es1688_probe(card, dev);
+ if (error < 0)
+ return error;
+ pnp_set_card_drvdata(pcard, card);
+ snd_es968_pnp_is_probed = 1;
+ return 0;
+}
+
+static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
+{
+ snd_card_free(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+ snd_es968_pnp_is_probed = 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_es968_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+ struct snd_es1688 *chip = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ return 0;
+}
+
+static int snd_es968_pnp_resume(struct pnp_card_link *pcard)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+ struct snd_es1688 *chip = card->private_data;
+
+ snd_es1688_reset(chip);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+static struct pnp_card_device_id snd_es968_pnpids[] = {
+ { .id = "ESS0968", .devs = { { "@@@0968" }, } },
+ { .id = "ESS0968", .devs = { { "ESS0968" }, } },
+ { .id = "", } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
+
+static struct pnp_card_driver es968_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DISABLE,
+ .name = DEV_NAME " PnP",
+ .id_table = snd_es968_pnpids,
+ .probe = snd_es968_pnp_detect,
+ .remove = __devexit_p(snd_es968_pnp_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_es968_pnp_suspend,
+ .resume = snd_es968_pnp_resume,
+#endif
+};
+#endif
+
static int __init alsa_card_es1688_init(void)
{
+#ifdef CONFIG_PNP
+ pnp_register_card_driver(&es968_pnpc_driver);
+ if (snd_es968_pnp_is_probed)
+ return 0;
+ pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
return isa_register_driver(&snd_es1688_driver, SNDRV_CARDS);
}
static void __exit alsa_card_es1688_exit(void)
{
- isa_unregister_driver(&snd_es1688_driver);
+ if (!snd_es968_pnp_is_probed) {
+ isa_unregister_driver(&snd_es1688_driver);
+ return;
+ }
+#ifdef CONFIG_PNP
+ pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
}
module_init(alsa_card_es1688_init);