11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ALSA driver for the Aureal Vortex family of soundprocessors. 31da177e4SLinus Torvalds * Author: Manuel Jander (mjander@embedded.cl) 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This driver is the result of the OpenVortex Project from Savannah 61da177e4SLinus Torvalds * (savannah.nongnu.org/projects/openvortex). I would like to thank 71da177e4SLinus Torvalds * the developers of OpenVortex, Jeff Muizelaar and Kester Maddock, from 81da177e4SLinus Torvalds * whom i got plenty of help, and their codebase was invaluable. 91da177e4SLinus Torvalds * Thanks to the ALSA developers, they helped a lot working out 101da177e4SLinus Torvalds * the ALSA part. 111da177e4SLinus Torvalds * Thanks also to Sourceforge for maintaining the old binary drivers, 121da177e4SLinus Torvalds * and the forum, where developers could comunicate. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Now at least i can play Legacy DOOM with MIDI music :-) 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include "au88x0.h" 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/pci.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/interrupt.h> 221da177e4SLinus Torvalds #include <linux/moduleparam.h> 231da177e4SLinus Torvalds #include <sound/initval.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds // module parameters (see "Module Parameters") 261da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 271da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 281da177e4SLinus Torvalds static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 291da177e4SLinus Torvalds static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 }; 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444); 321da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); 331da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444); 341da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); 351da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444); 361da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); 371da177e4SLinus Torvalds module_param_array(pcifix, int, NULL, 0444); 381da177e4SLinus Torvalds MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard."); 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds MODULE_DESCRIPTION("Aureal vortex"); 411da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 421da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, snd_vortex_ids); 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds static void vortex_fix_latency(struct pci_dev *vortex) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds int rc; 491da177e4SLinus Torvalds if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) { 501da177e4SLinus Torvalds printk(KERN_INFO CARD_NAME 511da177e4SLinus Torvalds ": vortex latency is 0xff\n"); 521da177e4SLinus Torvalds } else { 531da177e4SLinus Torvalds printk(KERN_WARNING CARD_NAME 541da177e4SLinus Torvalds ": could not set vortex latency: pci error 0x%x\n", rc); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static void vortex_fix_agp_bridge(struct pci_dev *via) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds int rc; 611da177e4SLinus Torvalds u8 value; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * only set the bit (Extend PCI#2 Internal Master for 651da177e4SLinus Torvalds * Efficient Handling of Dummy Requests) if the can 661da177e4SLinus Torvalds * read the config and it is not already set 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds if (!(rc = pci_read_config_byte(via, 0x42, &value)) 701da177e4SLinus Torvalds && ((value & 0x10) 711da177e4SLinus Torvalds || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) { 721da177e4SLinus Torvalds printk(KERN_INFO CARD_NAME 731da177e4SLinus Torvalds ": bridge config is 0x%x\n", value | 0x10); 741da177e4SLinus Torvalds } else { 751da177e4SLinus Torvalds printk(KERN_WARNING CARD_NAME 761da177e4SLinus Torvalds ": could not set vortex latency: pci error 0x%x\n", rc); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) 811da177e4SLinus Torvalds { 820dd119f7SJiri Slaby struct pci_dev *via = NULL; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* autodetect if workarounds are required */ 851da177e4SLinus Torvalds if (fix == 255) { 861da177e4SLinus Torvalds /* VIA KT133 */ 870dd119f7SJiri Slaby via = pci_get_device(PCI_VENDOR_ID_VIA, 880dd119f7SJiri Slaby PCI_DEVICE_ID_VIA_8365_1, NULL); 891da177e4SLinus Torvalds /* VIA Apollo */ 901da177e4SLinus Torvalds if (via == NULL) { 910dd119f7SJiri Slaby via = pci_get_device(PCI_VENDOR_ID_VIA, 920dd119f7SJiri Slaby PCI_DEVICE_ID_VIA_82C598_1, NULL); 931da177e4SLinus Torvalds /* AMD Irongate */ 940dd119f7SJiri Slaby if (via == NULL) 950dd119f7SJiri Slaby via = pci_get_device(PCI_VENDOR_ID_AMD, 960dd119f7SJiri Slaby PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds if (via) { 991da177e4SLinus Torvalds printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n"); 1001da177e4SLinus Torvalds vortex_fix_latency(vortex); 1011da177e4SLinus Torvalds vortex_fix_agp_bridge(via); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds } else { 1041da177e4SLinus Torvalds if (fix & 0x1) 1051da177e4SLinus Torvalds vortex_fix_latency(vortex); 1060dd119f7SJiri Slaby if ((fix & 0x2) && (via = pci_get_device(PCI_VENDOR_ID_VIA, 1070dd119f7SJiri Slaby PCI_DEVICE_ID_VIA_8365_1, NULL))) 1081da177e4SLinus Torvalds vortex_fix_agp_bridge(via); 1090dd119f7SJiri Slaby if ((fix & 0x4) && (via = pci_get_device(PCI_VENDOR_ID_VIA, 1100dd119f7SJiri Slaby PCI_DEVICE_ID_VIA_82C598_1, NULL))) 1111da177e4SLinus Torvalds vortex_fix_agp_bridge(via); 1120dd119f7SJiri Slaby if ((fix & 0x8) && (via = pci_get_device(PCI_VENDOR_ID_AMD, 1130dd119f7SJiri Slaby PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL))) 1141da177e4SLinus Torvalds vortex_fix_agp_bridge(via); 1151da177e4SLinus Torvalds } 1160dd119f7SJiri Slaby pci_dev_put(via); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds // component-destructor 1201da177e4SLinus Torvalds // (see "Management of Cards and Components") 1212fd16874STakashi Iwai static int snd_vortex_dev_free(struct snd_device *device) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds vortex_t *vortex = device->device_data; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds vortex_gameport_unregister(vortex); 1261da177e4SLinus Torvalds vortex_core_shutdown(vortex); 1271da177e4SLinus Torvalds // Take down PCI interface. 1281da177e4SLinus Torvalds synchronize_irq(vortex->irq); 1291da177e4SLinus Torvalds free_irq(vortex->irq, vortex); 1301da177e4SLinus Torvalds pci_release_regions(vortex->pci_dev); 1311da177e4SLinus Torvalds pci_disable_device(vortex->pci_dev); 1321da177e4SLinus Torvalds kfree(vortex); 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds return 0; 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds // chip-specific constructor 1381da177e4SLinus Torvalds // (see "Management of Cards and Components") 1391da177e4SLinus Torvalds static int __devinit 1402fd16874STakashi Iwai snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds vortex_t *chip; 1431da177e4SLinus Torvalds int err; 1442fd16874STakashi Iwai static struct snd_device_ops ops = { 1451da177e4SLinus Torvalds .dev_free = snd_vortex_dev_free, 1461da177e4SLinus Torvalds }; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds *rchip = NULL; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds // check PCI availability (DMA). 1511da177e4SLinus Torvalds if ((err = pci_enable_device(pci)) < 0) 1521da177e4SLinus Torvalds return err; 1531da177e4SLinus Torvalds if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) { 1541da177e4SLinus Torvalds printk(KERN_ERR "error to set DMA mask\n"); 1551da177e4SLinus Torvalds return -ENXIO; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds pci_set_dma_mask(pci, VORTEX_DMA_MASK); 1581da177e4SLinus Torvalds 159e560d8d8STakashi Iwai chip = kzalloc(sizeof(*chip), GFP_KERNEL); 1601da177e4SLinus Torvalds if (chip == NULL) 1611da177e4SLinus Torvalds return -ENOMEM; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds chip->card = card; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds // initialize the stuff 1661da177e4SLinus Torvalds chip->pci_dev = pci; 1671da177e4SLinus Torvalds chip->io = pci_resource_start(pci, 0); 1681da177e4SLinus Torvalds chip->vendor = pci->vendor; 1691da177e4SLinus Torvalds chip->device = pci->device; 1701da177e4SLinus Torvalds chip->card = card; 1711da177e4SLinus Torvalds chip->irq = -1; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds // (1) PCI resource allocation 1741da177e4SLinus Torvalds // Get MMIO area 1751da177e4SLinus Torvalds // 1761da177e4SLinus Torvalds if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0) 1771da177e4SLinus Torvalds goto regions_out; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), 1801da177e4SLinus Torvalds pci_resource_len(pci, 0)); 1811da177e4SLinus Torvalds if (!chip->mmio) { 1821da177e4SLinus Torvalds printk(KERN_ERR "MMIO area remap failed.\n"); 1831da177e4SLinus Torvalds err = -ENOMEM; 1841da177e4SLinus Torvalds goto ioremap_out; 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds /* Init audio core. 1881da177e4SLinus Torvalds * This must be done before we do request_irq otherwise we can get spurious 1891da177e4SLinus Torvalds * interupts that we do not handle properly and make a mess of things */ 1901da177e4SLinus Torvalds if ((err = vortex_core_init(chip)) != 0) { 1911da177e4SLinus Torvalds printk(KERN_ERR "hw core init failed\n"); 1921da177e4SLinus Torvalds goto core_out; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds if ((err = request_irq(pci->irq, vortex_interrupt, 1961da177e4SLinus Torvalds SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT, 1971da177e4SLinus Torvalds chip)) != 0) { 1981da177e4SLinus Torvalds printk(KERN_ERR "cannot grab irq\n"); 1991da177e4SLinus Torvalds goto irq_out; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds chip->irq = pci->irq; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds pci_set_master(pci); 2041da177e4SLinus Torvalds // End of PCI setup. 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds // Register alsa root device. 2071da177e4SLinus Torvalds if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { 2081da177e4SLinus Torvalds goto alloc_out; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds *rchip = chip; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds return 0; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds alloc_out: 2161da177e4SLinus Torvalds synchronize_irq(chip->irq); 2171da177e4SLinus Torvalds free_irq(chip->irq, chip); 2181da177e4SLinus Torvalds irq_out: 2191da177e4SLinus Torvalds vortex_core_shutdown(chip); 2201da177e4SLinus Torvalds core_out: 2211da177e4SLinus Torvalds iounmap(chip->mmio); 2221da177e4SLinus Torvalds ioremap_out: 2231da177e4SLinus Torvalds pci_release_regions(chip->pci_dev); 2241da177e4SLinus Torvalds regions_out: 2251da177e4SLinus Torvalds pci_disable_device(chip->pci_dev); 2261da177e4SLinus Torvalds //FIXME: this not the right place to unregister the gameport 2271da177e4SLinus Torvalds vortex_gameport_unregister(chip); 2281da177e4SLinus Torvalds return err; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds // constructor -- see "Constructor" sub-section 2321da177e4SLinus Torvalds static int __devinit 2331da177e4SLinus Torvalds snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) 2341da177e4SLinus Torvalds { 2351da177e4SLinus Torvalds static int dev; 2362fd16874STakashi Iwai struct snd_card *card; 2371da177e4SLinus Torvalds vortex_t *chip; 2381da177e4SLinus Torvalds int err; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds // (1) 2411da177e4SLinus Torvalds if (dev >= SNDRV_CARDS) 2421da177e4SLinus Torvalds return -ENODEV; 2431da177e4SLinus Torvalds if (!enable[dev]) { 2441da177e4SLinus Torvalds dev++; 2451da177e4SLinus Torvalds return -ENOENT; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds // (2) 2481da177e4SLinus Torvalds card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); 2491da177e4SLinus Torvalds if (card == NULL) 2501da177e4SLinus Torvalds return -ENOMEM; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds // (3) 2531da177e4SLinus Torvalds if ((err = snd_vortex_create(card, pci, &chip)) < 0) { 2541da177e4SLinus Torvalds snd_card_free(card); 2551da177e4SLinus Torvalds return err; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds snd_vortex_workaround(pci, pcifix[dev]); 2581da177e4SLinus Torvalds // (4) Alloc components. 2591da177e4SLinus Torvalds // ADB pcm. 2601da177e4SLinus Torvalds if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) { 2611da177e4SLinus Torvalds snd_card_free(card); 2621da177e4SLinus Torvalds return err; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds #ifndef CHIP_AU8820 2651da177e4SLinus Torvalds // ADB SPDIF 2661da177e4SLinus Torvalds if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) { 2671da177e4SLinus Torvalds snd_card_free(card); 2681da177e4SLinus Torvalds return err; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds // A3D 2711da177e4SLinus Torvalds if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) { 2721da177e4SLinus Torvalds snd_card_free(card); 2731da177e4SLinus Torvalds return err; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds #endif 2761da177e4SLinus Torvalds /* 2771da177e4SLinus Torvalds // ADB I2S 2781da177e4SLinus Torvalds if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) { 2791da177e4SLinus Torvalds snd_card_free(card); 2801da177e4SLinus Torvalds return err; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds #ifndef CHIP_AU8810 2841da177e4SLinus Torvalds // WT pcm. 2851da177e4SLinus Torvalds if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) { 2861da177e4SLinus Torvalds snd_card_free(card); 2871da177e4SLinus Torvalds return err; 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds #endif 2901da177e4SLinus Torvalds // snd_ac97_mixer and Vortex mixer. 2911da177e4SLinus Torvalds if ((err = snd_vortex_mixer(chip)) < 0) { 2921da177e4SLinus Torvalds snd_card_free(card); 2931da177e4SLinus Torvalds return err; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds if ((err = snd_vortex_midi(chip)) < 0) { 2961da177e4SLinus Torvalds snd_card_free(card); 2971da177e4SLinus Torvalds return err; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds vortex_gameport_register(chip); 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds #if 0 3031da177e4SLinus Torvalds if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH, 3041da177e4SLinus Torvalds sizeof(snd_vortex_synth_arg_t), &wave) < 0 3051da177e4SLinus Torvalds || wave == NULL) { 30699b359baSTakashi Iwai snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n"); 3071da177e4SLinus Torvalds } else { 3081da177e4SLinus Torvalds snd_vortex_synth_arg_t *arg; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); 3111da177e4SLinus Torvalds strcpy(wave->name, "Aureal Synth"); 3121da177e4SLinus Torvalds arg->hwptr = vortex; 3131da177e4SLinus Torvalds arg->index = 1; 3141da177e4SLinus Torvalds arg->seq_ports = seq_ports[dev]; 3151da177e4SLinus Torvalds arg->max_voices = max_synth_voices[dev]; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds #endif 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds // (5) 3201da177e4SLinus Torvalds strcpy(card->driver, CARD_NAME_SHORT); 3211da177e4SLinus Torvalds strcpy(card->shortname, CARD_NAME_SHORT); 3221da177e4SLinus Torvalds sprintf(card->longname, "%s at 0x%lx irq %i", 3231da177e4SLinus Torvalds card->shortname, chip->io, chip->irq); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds if ((err = pci_read_config_word(pci, PCI_DEVICE_ID, 3261da177e4SLinus Torvalds &(chip->device))) < 0) { 3271da177e4SLinus Torvalds snd_card_free(card); 3281da177e4SLinus Torvalds return err; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds if ((err = pci_read_config_word(pci, PCI_VENDOR_ID, 3311da177e4SLinus Torvalds &(chip->vendor))) < 0) { 3321da177e4SLinus Torvalds snd_card_free(card); 3331da177e4SLinus Torvalds return err; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds if ((err = pci_read_config_byte(pci, PCI_REVISION_ID, 3361da177e4SLinus Torvalds &(chip->rev))) < 0) { 3371da177e4SLinus Torvalds snd_card_free(card); 3381da177e4SLinus Torvalds return err; 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds #ifdef CHIP_AU8830 3411da177e4SLinus Torvalds if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) { 3421da177e4SLinus Torvalds printk(KERN_ALERT 3431da177e4SLinus Torvalds "vortex: The revision (%x) of your card has not been seen before.\n", 3441da177e4SLinus Torvalds chip->rev); 3451da177e4SLinus Torvalds printk(KERN_ALERT 3461da177e4SLinus Torvalds "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n"); 3471da177e4SLinus Torvalds snd_card_free(card); 3481da177e4SLinus Torvalds err = -ENODEV; 3491da177e4SLinus Torvalds return err; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds #endif 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds // (6) 3541da177e4SLinus Torvalds if ((err = snd_card_register(card)) < 0) { 3551da177e4SLinus Torvalds snd_card_free(card); 3561da177e4SLinus Torvalds return err; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds // (7) 3591da177e4SLinus Torvalds pci_set_drvdata(pci, card); 3601da177e4SLinus Torvalds dev++; 3611da177e4SLinus Torvalds vortex_connect_default(chip, 1); 3621da177e4SLinus Torvalds vortex_enable_int(chip); 3631da177e4SLinus Torvalds return 0; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds // destructor -- see "Destructor" sub-section 3671da177e4SLinus Torvalds static void __devexit snd_vortex_remove(struct pci_dev *pci) 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds snd_card_free(pci_get_drvdata(pci)); 3701da177e4SLinus Torvalds pci_set_drvdata(pci, NULL); 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds // pci_driver definition 3741da177e4SLinus Torvalds static struct pci_driver driver = { 3751da177e4SLinus Torvalds .name = CARD_NAME_SHORT, 3761da177e4SLinus Torvalds .id_table = snd_vortex_ids, 3771da177e4SLinus Torvalds .probe = snd_vortex_probe, 3781da177e4SLinus Torvalds .remove = __devexit_p(snd_vortex_remove), 3791da177e4SLinus Torvalds }; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds // initialization of the module 3821da177e4SLinus Torvalds static int __init alsa_card_vortex_init(void) 3831da177e4SLinus Torvalds { 38401d25d46STakashi Iwai return pci_register_driver(&driver); 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds // clean up the module 3881da177e4SLinus Torvalds static void __exit alsa_card_vortex_exit(void) 3891da177e4SLinus Torvalds { 3901da177e4SLinus Torvalds pci_unregister_driver(&driver); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds module_init(alsa_card_vortex_init) 3941da177e4SLinus Torvalds module_exit(alsa_card_vortex_exit) 395