Loading sound/isa/opl3sa2.c +228 −200 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <sound/driver.h> #include <linux/init.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/pm.h> #include <linux/slab.h> Loading Loading @@ -126,21 +128,12 @@ struct snd_opl3sa2 { struct snd_hwdep *synth; struct snd_rawmidi *rmidi; struct snd_cs4231 *cs4231; #ifdef CONFIG_PNP struct pnp_dev *dev; #endif unsigned char ctlregs[0x20]; int ymode; /* SL added */ struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; #ifdef CONFIG_PM void (*cs4231_suspend)(struct snd_cs4231 *); void (*cs4231_resume)(struct snd_cs4231 *); #endif }; static struct snd_card *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; #define PFX "opl3sa2: " #ifdef CONFIG_PNP Loading Loading @@ -539,11 +532,10 @@ static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) #ifdef CONFIG_PM static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) { struct snd_opl3sa2 *chip = card->pm_private_data; snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */ chip->cs4231_suspend(chip->cs4231); struct snd_opl3sa2 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->cs4231->suspend(chip->cs4231); /* power down */ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); Loading @@ -552,7 +544,7 @@ static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) static int snd_opl3sa2_resume(struct snd_card *card) { struct snd_opl3sa2 *chip = card->pm_private_data; struct snd_opl3sa2 *chip = card->private_data; int i; /* power up */ Loading @@ -568,23 +560,20 @@ static int snd_opl3sa2_resume(struct snd_card *card) snd_opl3sa2_write(chip, i, chip->ctlregs[i]); } /* restore cs4231 */ chip->cs4231_resume(chip->cs4231); chip->cs4231->resume(chip->cs4231); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ #ifdef CONFIG_PNP static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, struct pnp_dev *pdev, int isapnp) struct pnp_dev *pdev) { 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; Loading @@ -607,7 +596,7 @@ static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, if (irq[dev] != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0 && isapnp) if (err < 0) snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { Loading @@ -628,111 +617,47 @@ static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, 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, struct snd_opl3sa2 *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(struct snd_opl3sa2 *chip) static void snd_opl3sa2_free(struct snd_card *card) { struct snd_opl3sa2 *chip = card->private_data; if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); release_and_free_resource(chip->res_port); kfree(chip); return 0; } static int snd_opl3sa2_dev_free(struct snd_device *device) { struct snd_opl3sa2 *chip = device->device_data; return snd_opl3sa2_free(chip); } #ifdef CONFIG_PNP #define is_isapnp_selected(dev) isapnp[dev] #else #define is_isapnp_selected(dev) 0 #endif static int __devinit snd_opl3sa2_probe(int dev, struct pnp_dev *pdev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) static struct snd_card *snd_opl3sa2_card_new(int dev) { int xirq, xdma1, xdma2; struct snd_card *card; struct snd_opl3sa2 *chip; struct snd_cs4231 *cs4231; struct snd_opl3 *opl3; static struct snd_device_ops ops = { .dev_free = snd_opl3sa2_dev_free, }; int err; if (! is_isapnp_selected(dev)) { if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify port\n"); return -EINVAL; } if (wss_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify wss_port\n"); return -EINVAL; } if (fm_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify fm_port\n"); return -EINVAL; } if (midi_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify midi_port\n"); return -EINVAL; } } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2)); if (card == NULL) return -ENOMEM; return NULL; strcpy(card->driver, "OPL3SA2"); strcpy(card->shortname, "Yamaha OPL3-SA2"); chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { err = -ENOMEM; goto __error; } chip = card->private_data; spin_lock_init(&chip->reg_lock); chip->irq = -1; if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; #ifdef CONFIG_PNP 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); } #endif chip->ymode = opl3sa3_ymode[dev] & 0x03 ; /* initialise this card from supplied (or default) parameter*/ chip->card = card; card->private_free = snd_opl3sa2_free; return card; } static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_opl3sa2 *chip; struct snd_cs4231 *cs4231; struct snd_opl3 *opl3; int err; /* initialise this card from supplied (or default) parameter*/ chip = card->private_data; chip->ymode = opl3sa3_ymode[dev] & 0x03 ; chip->port = port[dev]; xirq = irq[dev]; xdma1 = dma1[dev]; Loading @@ -740,11 +665,10 @@ static int __devinit snd_opl3sa2_probe(int dev, if (xdma2 < 0) chip->single_dma = 1; if ((err = snd_opl3sa2_detect(chip)) < 0) goto __error; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", (void *)chip)) { return err; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", chip)) { snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); err = -ENODEV; goto __error; return -ENODEV; } chip->irq = xirq; if ((err = snd_cs4231_create(card, Loading @@ -754,64 +678,39 @@ static int __devinit snd_opl3sa2_probe(int dev, CS4231_HWSHARE_IRQ, &cs4231)) < 0) { snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4); goto __error; return err; } chip->cs4231 = cs4231; if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) goto __error; return err; if ((err = snd_cs4231_mixer(cs4231)) < 0) goto __error; return err; if ((err = snd_opl3sa2_mixer(chip)) < 0) goto __error; return err; if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0) goto __error; return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { if ((err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) goto __error; return err; if ((err = snd_opl3_timer_new(opl3, 1, 2)) < 0) goto __error; return err; if ((err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth)) < 0) goto __error; return err; } if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, midi_port[dev], 0, xirq, 0, &chip->rmidi)) < 0) goto __error; return err; } #ifdef CONFIG_PM chip->cs4231_suspend = chip->cs4231->suspend; chip->cs4231_resume = chip->cs4231->resume; /* now clear callbacks for cs4231 */ chip->cs4231->suspend = NULL; chip->cs4231->resume = NULL; snd_card_set_isa_pm_callback(card, snd_opl3sa2_suspend, snd_opl3sa2_resume, chip); #endif sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", card->shortname, chip->port, xirq, xdma1); if (dma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); if ((err = snd_card_set_generic_dev(card)) < 0) goto __error; if ((err = snd_card_register(card)) < 0) goto __error; if (pdev) pnp_set_drvdata(pdev, card); else if (pcard) pnp_set_card_drvdata(pcard, card); else snd_opl3sa2_legacy[dev] = card; return 0; __error: snd_card_free(card); return err; return snd_card_register(card); } #ifdef CONFIG_PNP Loading @@ -819,62 +718,114 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, const struct pnp_device_id *id) { static int dev; int res; int err; struct snd_card *card; if (pnp_device_is_isapnp(pdev)) return -ENOENT; /* we have another procedure - card */ for (; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || !isapnp[dev]) continue; res = snd_opl3sa2_probe(dev, pdev, NULL, NULL); if (res < 0) return res; dev++; return 0; if (enable[dev] && isapnp[dev]) break; } if (dev >= SNDRV_CARDS) return -ENODEV; card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } pnp_set_drvdata(pdev, card); dev++; return 0; } static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev) { struct snd_card *card = (struct snd_card *) pnp_get_drvdata(pdev); snd_card_free(pnp_get_drvdata(pdev)); pnp_set_drvdata(pdev, NULL); } snd_card_disconnect(card); snd_card_free_in_thread(card); #ifdef CONFIG_PM static int snd_opl3sa2_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) { return snd_opl3sa2_suspend(pnp_get_drvdata(pdev), state); } static int snd_opl3sa2_pnp_resume(struct pnp_dev *pdev) { return snd_opl3sa2_resume(pnp_get_drvdata(pdev)); } #endif static struct pnp_driver opl3sa2_pnp_driver = { .name = "opl3sa2-pnpbios", .id_table = snd_opl3sa2_pnpbiosids, .probe = snd_opl3sa2_pnp_detect, .remove = __devexit_p(snd_opl3sa2_pnp_remove), #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_suspend, .resume = snd_opl3sa2_pnp_resume, #endif }; static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card, static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, const struct pnp_card_device_id *id) { static int dev; int res; struct pnp_dev *pdev; int err; struct snd_card *card; pdev = pnp_request_card_device(pcard, id->devs[0].id, NULL); if (pdev == NULL) return -EBUSY; for (; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; if (is_isapnp_selected(dev)) continue; res = snd_opl3sa2_probe(dev, NULL, card, id); if (res < 0) return res; dev++; return 0; if (enable[dev] && isapnp[dev]) break; } if (dev >= SNDRV_CARDS) return -ENODEV; card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } pnp_set_card_drvdata(pcard, card); dev++; return 0; } static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard) { struct snd_card *card = (struct snd_card *) pnp_get_card_drvdata(pcard); snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); } snd_card_disconnect(card); snd_card_free_in_thread(card); #ifdef CONFIG_PM static int snd_opl3sa2_pnp_csuspend(struct pnp_card_link *pcard, pm_message_t state) { return snd_opl3sa2_suspend(pnp_get_card_drvdata(pcard), state); } static int snd_opl3sa2_pnp_cresume(struct pnp_card_link *pcard) { return snd_opl3sa2_resume(pnp_get_card_drvdata(pcard)); } #endif static struct pnp_card_driver opl3sa2_pnpc_driver = { .flags = PNP_DRIVER_RES_DISABLE, Loading @@ -882,35 +833,118 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = { .id_table = snd_opl3sa2_pnpids, .probe = snd_opl3sa2_pnp_cdetect, .remove = __devexit_p(snd_opl3sa2_pnp_cremove), #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_csuspend, .resume = snd_opl3sa2_pnp_cresume, #endif }; #endif /* CONFIG_PNP */ static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) { struct snd_card *card; int err; int dev = pdev->id; if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify port\n"); return -EINVAL; } if (wss_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify wss_port\n"); return -EINVAL; } if (fm_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify fm_port\n"); return -EINVAL; } if (midi_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify midi_port\n"); return -EINVAL; } card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } platform_set_drvdata(pdev, card); return 0; } static int snd_opl3sa2_nonpnp_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); return 0; } #ifdef CONFIG_PM static int snd_opl3sa2_nonpnp_suspend(struct platform_device *dev, pm_message_t state) { return snd_opl3sa2_suspend(platform_get_drvdata(dev), state); } static int snd_opl3sa2_nonpnp_resume(struct platform_device *dev) { return snd_opl3sa2_resume(platform_get_drvdata(dev)); } #endif #define OPL3SA2_DRIVER "snd_opl3sa2" static struct platform_driver snd_opl3sa2_nonpnp_driver = { .probe = snd_opl3sa2_nonpnp_probe, .remove = snd_opl3sa2_nonpnp_remove, #ifdef CONFIG_PM .suspend = snd_opl3sa2_nonpnp_suspend, .resume = snd_opl3sa2_nonpnp_resume, #endif .driver = { .name = OPL3SA2_DRIVER }, }; static int __init alsa_card_opl3sa2_init(void) { int dev, cards = 0; int i, err, cards = 0; for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0) return err; for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { struct platform_device *device; #ifdef CONFIG_PNP if (isapnp[dev]) if (isapnp[i]) continue; #endif if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0) device = platform_device_register_simple(OPL3SA2_DRIVER, i, NULL, 0); if (IS_ERR(device)) { err = PTR_ERR(device); platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); return err; } cards++; } #ifdef CONFIG_PNP cards += pnp_register_driver(&opl3sa2_pnp_driver); cards += pnp_register_card_driver(&opl3sa2_pnpc_driver); #endif err = pnp_register_driver(&opl3sa2_pnp_driver); if (err > 0) cards += err; err = pnp_register_card_driver(&opl3sa2_pnpc_driver); if (err > 0) cards += err; if (!cards) { #ifdef MODULE snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); #endif #ifdef CONFIG_PNP pnp_unregister_card_driver(&opl3sa2_pnpc_driver); pnp_unregister_driver(&opl3sa2_pnp_driver); #endif platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); return -ENODEV; } return 0; Loading @@ -918,15 +952,9 @@ static int __init alsa_card_opl3sa2_init(void) static void __exit alsa_card_opl3sa2_exit(void) { int idx; #ifdef CONFIG_PNP /* PnP cards first */ pnp_unregister_card_driver(&opl3sa2_pnpc_driver); pnp_unregister_driver(&opl3sa2_pnp_driver); #endif for (idx = 0; idx < SNDRV_CARDS; idx++) snd_card_free(snd_opl3sa2_legacy[idx]); platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); } module_init(alsa_card_opl3sa2_init) Loading Loading
sound/isa/opl3sa2.c +228 −200 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <sound/driver.h> #include <linux/init.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/pm.h> #include <linux/slab.h> Loading Loading @@ -126,21 +128,12 @@ struct snd_opl3sa2 { struct snd_hwdep *synth; struct snd_rawmidi *rmidi; struct snd_cs4231 *cs4231; #ifdef CONFIG_PNP struct pnp_dev *dev; #endif unsigned char ctlregs[0x20]; int ymode; /* SL added */ struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; #ifdef CONFIG_PM void (*cs4231_suspend)(struct snd_cs4231 *); void (*cs4231_resume)(struct snd_cs4231 *); #endif }; static struct snd_card *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; #define PFX "opl3sa2: " #ifdef CONFIG_PNP Loading Loading @@ -539,11 +532,10 @@ static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) #ifdef CONFIG_PM static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) { struct snd_opl3sa2 *chip = card->pm_private_data; snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */ chip->cs4231_suspend(chip->cs4231); struct snd_opl3sa2 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->cs4231->suspend(chip->cs4231); /* power down */ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); Loading @@ -552,7 +544,7 @@ static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) static int snd_opl3sa2_resume(struct snd_card *card) { struct snd_opl3sa2 *chip = card->pm_private_data; struct snd_opl3sa2 *chip = card->private_data; int i; /* power up */ Loading @@ -568,23 +560,20 @@ static int snd_opl3sa2_resume(struct snd_card *card) snd_opl3sa2_write(chip, i, chip->ctlregs[i]); } /* restore cs4231 */ chip->cs4231_resume(chip->cs4231); chip->cs4231->resume(chip->cs4231); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ #ifdef CONFIG_PNP static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, struct pnp_dev *pdev, int isapnp) struct pnp_dev *pdev) { 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; Loading @@ -607,7 +596,7 @@ static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, if (irq[dev] != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0 && isapnp) if (err < 0) snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { Loading @@ -628,111 +617,47 @@ static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, 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, struct snd_opl3sa2 *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(struct snd_opl3sa2 *chip) static void snd_opl3sa2_free(struct snd_card *card) { struct snd_opl3sa2 *chip = card->private_data; if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); release_and_free_resource(chip->res_port); kfree(chip); return 0; } static int snd_opl3sa2_dev_free(struct snd_device *device) { struct snd_opl3sa2 *chip = device->device_data; return snd_opl3sa2_free(chip); } #ifdef CONFIG_PNP #define is_isapnp_selected(dev) isapnp[dev] #else #define is_isapnp_selected(dev) 0 #endif static int __devinit snd_opl3sa2_probe(int dev, struct pnp_dev *pdev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) static struct snd_card *snd_opl3sa2_card_new(int dev) { int xirq, xdma1, xdma2; struct snd_card *card; struct snd_opl3sa2 *chip; struct snd_cs4231 *cs4231; struct snd_opl3 *opl3; static struct snd_device_ops ops = { .dev_free = snd_opl3sa2_dev_free, }; int err; if (! is_isapnp_selected(dev)) { if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify port\n"); return -EINVAL; } if (wss_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify wss_port\n"); return -EINVAL; } if (fm_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify fm_port\n"); return -EINVAL; } if (midi_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify midi_port\n"); return -EINVAL; } } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2)); if (card == NULL) return -ENOMEM; return NULL; strcpy(card->driver, "OPL3SA2"); strcpy(card->shortname, "Yamaha OPL3-SA2"); chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { err = -ENOMEM; goto __error; } chip = card->private_data; spin_lock_init(&chip->reg_lock); chip->irq = -1; if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; #ifdef CONFIG_PNP 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); } #endif chip->ymode = opl3sa3_ymode[dev] & 0x03 ; /* initialise this card from supplied (or default) parameter*/ chip->card = card; card->private_free = snd_opl3sa2_free; return card; } static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_opl3sa2 *chip; struct snd_cs4231 *cs4231; struct snd_opl3 *opl3; int err; /* initialise this card from supplied (or default) parameter*/ chip = card->private_data; chip->ymode = opl3sa3_ymode[dev] & 0x03 ; chip->port = port[dev]; xirq = irq[dev]; xdma1 = dma1[dev]; Loading @@ -740,11 +665,10 @@ static int __devinit snd_opl3sa2_probe(int dev, if (xdma2 < 0) chip->single_dma = 1; if ((err = snd_opl3sa2_detect(chip)) < 0) goto __error; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", (void *)chip)) { return err; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", chip)) { snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); err = -ENODEV; goto __error; return -ENODEV; } chip->irq = xirq; if ((err = snd_cs4231_create(card, Loading @@ -754,64 +678,39 @@ static int __devinit snd_opl3sa2_probe(int dev, CS4231_HWSHARE_IRQ, &cs4231)) < 0) { snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4); goto __error; return err; } chip->cs4231 = cs4231; if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) goto __error; return err; if ((err = snd_cs4231_mixer(cs4231)) < 0) goto __error; return err; if ((err = snd_opl3sa2_mixer(chip)) < 0) goto __error; return err; if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0) goto __error; return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { if ((err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) goto __error; return err; if ((err = snd_opl3_timer_new(opl3, 1, 2)) < 0) goto __error; return err; if ((err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth)) < 0) goto __error; return err; } if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, midi_port[dev], 0, xirq, 0, &chip->rmidi)) < 0) goto __error; return err; } #ifdef CONFIG_PM chip->cs4231_suspend = chip->cs4231->suspend; chip->cs4231_resume = chip->cs4231->resume; /* now clear callbacks for cs4231 */ chip->cs4231->suspend = NULL; chip->cs4231->resume = NULL; snd_card_set_isa_pm_callback(card, snd_opl3sa2_suspend, snd_opl3sa2_resume, chip); #endif sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", card->shortname, chip->port, xirq, xdma1); if (dma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); if ((err = snd_card_set_generic_dev(card)) < 0) goto __error; if ((err = snd_card_register(card)) < 0) goto __error; if (pdev) pnp_set_drvdata(pdev, card); else if (pcard) pnp_set_card_drvdata(pcard, card); else snd_opl3sa2_legacy[dev] = card; return 0; __error: snd_card_free(card); return err; return snd_card_register(card); } #ifdef CONFIG_PNP Loading @@ -819,62 +718,114 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, const struct pnp_device_id *id) { static int dev; int res; int err; struct snd_card *card; if (pnp_device_is_isapnp(pdev)) return -ENOENT; /* we have another procedure - card */ for (; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || !isapnp[dev]) continue; res = snd_opl3sa2_probe(dev, pdev, NULL, NULL); if (res < 0) return res; dev++; return 0; if (enable[dev] && isapnp[dev]) break; } if (dev >= SNDRV_CARDS) return -ENODEV; card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } pnp_set_drvdata(pdev, card); dev++; return 0; } static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev) { struct snd_card *card = (struct snd_card *) pnp_get_drvdata(pdev); snd_card_free(pnp_get_drvdata(pdev)); pnp_set_drvdata(pdev, NULL); } snd_card_disconnect(card); snd_card_free_in_thread(card); #ifdef CONFIG_PM static int snd_opl3sa2_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) { return snd_opl3sa2_suspend(pnp_get_drvdata(pdev), state); } static int snd_opl3sa2_pnp_resume(struct pnp_dev *pdev) { return snd_opl3sa2_resume(pnp_get_drvdata(pdev)); } #endif static struct pnp_driver opl3sa2_pnp_driver = { .name = "opl3sa2-pnpbios", .id_table = snd_opl3sa2_pnpbiosids, .probe = snd_opl3sa2_pnp_detect, .remove = __devexit_p(snd_opl3sa2_pnp_remove), #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_suspend, .resume = snd_opl3sa2_pnp_resume, #endif }; static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card, static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, const struct pnp_card_device_id *id) { static int dev; int res; struct pnp_dev *pdev; int err; struct snd_card *card; pdev = pnp_request_card_device(pcard, id->devs[0].id, NULL); if (pdev == NULL) return -EBUSY; for (; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; if (is_isapnp_selected(dev)) continue; res = snd_opl3sa2_probe(dev, NULL, card, id); if (res < 0) return res; dev++; return 0; if (enable[dev] && isapnp[dev]) break; } if (dev >= SNDRV_CARDS) return -ENODEV; card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } pnp_set_card_drvdata(pcard, card); dev++; return 0; } static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard) { struct snd_card *card = (struct snd_card *) pnp_get_card_drvdata(pcard); snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); } snd_card_disconnect(card); snd_card_free_in_thread(card); #ifdef CONFIG_PM static int snd_opl3sa2_pnp_csuspend(struct pnp_card_link *pcard, pm_message_t state) { return snd_opl3sa2_suspend(pnp_get_card_drvdata(pcard), state); } static int snd_opl3sa2_pnp_cresume(struct pnp_card_link *pcard) { return snd_opl3sa2_resume(pnp_get_card_drvdata(pcard)); } #endif static struct pnp_card_driver opl3sa2_pnpc_driver = { .flags = PNP_DRIVER_RES_DISABLE, Loading @@ -882,35 +833,118 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = { .id_table = snd_opl3sa2_pnpids, .probe = snd_opl3sa2_pnp_cdetect, .remove = __devexit_p(snd_opl3sa2_pnp_cremove), #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_csuspend, .resume = snd_opl3sa2_pnp_cresume, #endif }; #endif /* CONFIG_PNP */ static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) { struct snd_card *card; int err; int dev = pdev->id; if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify port\n"); return -EINVAL; } if (wss_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify wss_port\n"); return -EINVAL; } if (fm_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify fm_port\n"); return -EINVAL; } if (midi_port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR PFX "specify midi_port\n"); return -EINVAL; } card = snd_opl3sa2_card_new(dev); if (! card) return -ENOMEM; snd_card_set_dev(card, &pdev->dev); if ((err = snd_opl3sa2_probe(card, dev)) < 0) { snd_card_free(card); return err; } platform_set_drvdata(pdev, card); return 0; } static int snd_opl3sa2_nonpnp_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); return 0; } #ifdef CONFIG_PM static int snd_opl3sa2_nonpnp_suspend(struct platform_device *dev, pm_message_t state) { return snd_opl3sa2_suspend(platform_get_drvdata(dev), state); } static int snd_opl3sa2_nonpnp_resume(struct platform_device *dev) { return snd_opl3sa2_resume(platform_get_drvdata(dev)); } #endif #define OPL3SA2_DRIVER "snd_opl3sa2" static struct platform_driver snd_opl3sa2_nonpnp_driver = { .probe = snd_opl3sa2_nonpnp_probe, .remove = snd_opl3sa2_nonpnp_remove, #ifdef CONFIG_PM .suspend = snd_opl3sa2_nonpnp_suspend, .resume = snd_opl3sa2_nonpnp_resume, #endif .driver = { .name = OPL3SA2_DRIVER }, }; static int __init alsa_card_opl3sa2_init(void) { int dev, cards = 0; int i, err, cards = 0; for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0) return err; for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { struct platform_device *device; #ifdef CONFIG_PNP if (isapnp[dev]) if (isapnp[i]) continue; #endif if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0) device = platform_device_register_simple(OPL3SA2_DRIVER, i, NULL, 0); if (IS_ERR(device)) { err = PTR_ERR(device); platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); return err; } cards++; } #ifdef CONFIG_PNP cards += pnp_register_driver(&opl3sa2_pnp_driver); cards += pnp_register_card_driver(&opl3sa2_pnpc_driver); #endif err = pnp_register_driver(&opl3sa2_pnp_driver); if (err > 0) cards += err; err = pnp_register_card_driver(&opl3sa2_pnpc_driver); if (err > 0) cards += err; if (!cards) { #ifdef MODULE snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); #endif #ifdef CONFIG_PNP pnp_unregister_card_driver(&opl3sa2_pnpc_driver); pnp_unregister_driver(&opl3sa2_pnp_driver); #endif platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); return -ENODEV; } return 0; Loading @@ -918,15 +952,9 @@ static int __init alsa_card_opl3sa2_init(void) static void __exit alsa_card_opl3sa2_exit(void) { int idx; #ifdef CONFIG_PNP /* PnP cards first */ pnp_unregister_card_driver(&opl3sa2_pnpc_driver); pnp_unregister_driver(&opl3sa2_pnp_driver); #endif for (idx = 0; idx < SNDRV_CARDS; idx++) snd_card_free(snd_opl3sa2_legacy[idx]); platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); } module_init(alsa_card_opl3sa2_init) Loading