/* * ALSA driver for the Aureal Vortex family of soundprocessors. * Author: Manuel Jander (mjander@embedded.cl) * * This driver is the result of the OpenVortex Project from Savannah * (savannah.nongnu.org/projects/openvortex). I would like to thank * the developers of OpenVortex, Jeff Muizelar and Kester Maddock, from * whom i got plenty of help, and their codebase was invaluable. * Thanks to the ALSA developers, they helped a lot working out * the ALSA part. * Thanks also to Sourceforge for maintaining the old binary drivers, * and the forum, where developer could comunicate. * * Now at least i can play Legacy DOOM with MIDI music :-) */ #include "au88x0.h" #include #include #include #define SNDRV_GET_ID #include // module parameters (see "Module Parameters") static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; #define CARD_NAME "Aureal Vortex 3D Sound Processor" MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_DESCRIPTION("Aureal vortex"); MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); #ifndef MODULE /* format is: snd-mychip=enable,index,id */ static int __init alsa_card_vortex_setup(char *str) { static unsigned __initdata nr_dev = 0; if (nr_dev >= SNDRV_CARDS) return 0; (void) (get_option(&str, &enable[nr_dev]) == 2 && get_option(&str, &index[nr_dev]) == 2 && get_id(&str, &id[nr_dev]) == 2); nr_dev++; return 1; } __setup("snd-mychip=", alsa_card_vortex_setup); #endif /* ifndef MODULE */ // PCI IDs /* static struct pci_device_id snd_vortex_ids[] __devinitdata = { {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,}, {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,}, {0,} }; */ MODULE_DEVICE_TABLE(pci, snd_vortex_ids); // chip-specific destructor // (see "PCI Resource Managements") static int snd_vortex_free(vortex_t * vortex) { vortex_gameport_unregister(vortex); vortex_core_shutdown(vortex); // Take down PCI interface. synchronize_irq(vortex->irq); free_irq(vortex->irq, vortex); pci_release_regions(vortex->pci_dev); pci_disable_device(vortex->pci_dev); snd_magic_kfree(vortex); return 0; } // component-destructor // (see "Management of Cards and Components") static int snd_vortex_dev_free(snd_device_t * device) { vortex_t *vortex = snd_magic_cast(vortex_t, device->device_data, return -ENXIO); return snd_vortex_free(vortex); } // chip-specific constructor // (see "Management of Cards and Components") static int __devinit snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip) { vortex_t *chip; // vortex int err; static snd_device_ops_t ops = { .dev_free = snd_vortex_dev_free, }; *rchip = NULL; // check PCI availability (DMA). if ((err = pci_enable_device(pci)) < 0) return err; if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) { printk(KERN_ERR "error to set DMA mask\n"); return -ENXIO; } pci_set_dma_mask(pci, VORTEX_DMA_MASK); if (pci->irq == 0) return -ENODEV; chip = snd_magic_kcalloc(vortex_t, 0, GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->card = card; // initialize the stuff chip->pci_dev = pci; chip->io = pci_resource_start(pci, 0); chip->vendor = pci->vendor; chip->device = pci->device; chip->card = card; chip->irq = -1; // (1) PCI resource allocation // Get MMIO area. if (!request_mem_region(pci_resource_start(pci, 0), pci_resource_len(pci, 0), "vortex")) { snd_vortex_free(chip); printk(KERN_ERR "cannot allocate mmio area.\n"); return -EBUSY; } //chip->mmio = ioremap_nocache(pci_resource_start(pci,0), pci_resource_len(pci,0)); chip->mmio = ioremap(pci_resource_start(pci,0), pci_resource_len(pci,0)); if (!chip->mmio) { snd_vortex_free(chip); printk(KERN_ERR "MMIO area remap failed.\n"); return -EBUSY; } // Get I/O ports. if (check_region(pci_resource_start(pci, 1), 8)) { snd_vortex_free(chip); printk(KERN_ERR "cannot allocate I/O port0.\n"); return -EBUSY; } chip->port0 = request_region(pci_resource_start(pci, 1), 8, "vortex"); if (check_region(pci_resource_start(pci, 2), 8)) { snd_vortex_free(chip); printk(KERN_ERR "cannot allocate the I/O port1.\n"); return -EBUSY; } chip->port1 = request_region(pci_resource_start(pci, 2), 8, "vortex"); if (request_irq(pci->irq, vortex_interrupt, SA_INTERRUPT | SA_SHIRQ, "vortex", (void *) chip)) { snd_vortex_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; pci_set_master(pci); // End of PCI setup. // Init audio core. vortex_core_init(chip); // Register alsa root device. if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_vortex_free(chip); return err; } *rchip = chip; return 0; } // constructor -- see "Constructor" sub-section static int __devinit snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; snd_card_t *card; vortex_t *chip; int err; // (1) if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } // (2) card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; // (3) if ((err = snd_vortex_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; } // (4) Alloc components. // ADB pcm. if ((err = snd_vortex_new_pcm(chip, 0, NR_ADB)) < 0) { snd_card_free(card); return err; } // WT pcm. if ((err = snd_vortex_new_pcm(chip, 1, NR_WT)) < 0) { snd_card_free(card); return err; } // snd_ac97_mixer and Vortex mixer. if ((err = snd_vortex_mixer(chip)) < 0) { snd_card_free(card); return err; } if ((err = snd_vortex_midi(chip)) < 0) { snd_card_free(card); return err; } if ((err = vortex_gameport_register(chip)) < 0) { snd_card_free(card); return err; } #if 0 if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH, sizeof(snd_vortex_synth_arg_t), &wave) < 0 || wave == NULL) { snd_printk("can't initialize Vortex wavetable synth\n"); } else { snd_vortex_synth_arg_t *arg; arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); strcpy(wave->name, "Vortex Synth"); arg->hwptr = vortex; arg->index = 1; arg->seq_ports = seq_ports[dev]; arg->max_voices = max_synth_voices[dev]; } #endif // (5) strcpy(card->driver, "vortex Vortex"); strcpy(card->shortname, "vortex"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->io, chip->irq); // (6) if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } // (7) pci_set_drvdata(pci, chip); dev++; return 0; } // destructor -- see "Destructor" sub-section static void __devexit snd_vortex_remove(struct pci_dev *pci) { vortex_t *vortex = snd_magic_cast(vortex_t, pci_get_drvdata(pci), return); if (vortex) { // Release ALSA stuff. snd_card_free(vortex->card); // Free Vortex struct. pci_set_drvdata(pci, NULL); } else printk("snd_vortex_remove called more than one time!\n"); } // pci_driver definition static struct pci_driver driver = { .name = "Aureal Vortex", .id_table = snd_vortex_ids, .probe = snd_vortex_probe, .remove = __devexit_p(snd_vortex_remove), }; // initialization of the module static int __init alsa_card_vortex_init(void) { int err; if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE printk(KERN_ERR "vortex soundcard not found " "or device busy\n"); #endif return err; } return 0; } // clean up the module static void __exit alsa_card_vortex_exit(void) { pci_unregister_driver(&driver); } module_init(alsa_card_vortex_init) module_exit(alsa_card_vortex_exit) // for old kernels only EXPORT_NO_SYMBOLS;