/[openvortex]/alsa/pci/au88x0/au88x0.c
ViewVC logotype

Diff of /alsa/pci/au88x0/au88x0.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.16 by mjander, Thu Aug 7 01:58:51 2003 UTC revision 1.17 by vizard, Sun Aug 10 20:00:33 2003 UTC
# Line 1  Line 1 
1  #define __NO_VERSION__  /*
2  #include "../../alsa-kernel/pci/au88x0/au88x0.c"   * ALSA driver for the Aureal Vortex family of soundprocessors.
3     * Author: Manuel Jander (mjander@embedded.cl)
4     *
5     *   This driver is the result of the OpenVortex Project from Savannah
6     * (savannah.nongnu.org/projects/openvortex). I would like to thank
7     * the developers of OpenVortex, Jeff Muizelar and Kester Maddock, from
8     * whom i got plenty of help, and their codebase was invaluable.
9     *   Thanks to the ALSA developers, they helped a lot working out
10     * the ALSA part.
11     *   Thanks also to Sourceforge for maintaining the old binary drivers,
12     * and the forum, where developers could comunicate.
13     *
14     * Now at least i can play Legacy DOOM with MIDI music :-)
15     */
16    
17    #include "au88x0.h"
18    #include <linux/init.h>
19    #include <linux/pci.h>
20    #include <linux/slab.h>
21    #include <linux/interrupt.h>
22    #define SNDRV_GET_ID
23    #include <sound/initval.h>
24    
25    // module parameters (see "Module Parameters")
26    static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
27    static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
28    static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
29    
30    MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
31    MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
32    MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
33    MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
34    MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
35    MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
36    MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
37    MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
38    MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
39    
40    MODULE_DESCRIPTION("Aureal vortex");
41    MODULE_CLASSES("{sound}");
42    MODULE_LICENSE("GPL");
43    MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
44    
45    #ifndef MODULE
46    /* format is: snd-mychip=enable,index,id */
47    static int __init alsa_card_vortex_setup(char *str) {
48        static unsigned __initdata nr_dev = 0;
49    
50        if (nr_dev >= SNDRV_CARDS)
51            return 0;
52        (void) (get_option(&str, &enable[nr_dev]) == 2 &&
53                get_option(&str, &index[nr_dev]) == 2 &&
54                get_id(&str, &id[nr_dev]) == 2);
55        nr_dev++;
56        return 1;
57    }
58    __setup("snd-au88x0=", alsa_card_vortex_setup);
59    #endif /* ifndef MODULE */
60    
61    
62    MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
63    
64    
65    // component-destructor
66    // (see "Management of Cards and Components")
67    static int snd_vortex_dev_free(snd_device_t *device) {
68        vortex_t *vortex = snd_magic_cast(vortex_t, device->device_data,
69                                          return -ENXIO);
70        
71        vortex_gameport_unregister(vortex);
72        vortex_core_shutdown(vortex);
73        // Take down PCI interface.
74        synchronize_irq(vortex->irq);
75        free_irq(vortex->irq, vortex);
76        pci_release_regions(vortex->pci_dev);
77        pci_disable_device(vortex->pci_dev);
78        snd_magic_kfree(vortex);
79    
80        return 0;
81    }
82    
83    // chip-specific constructor
84    // (see "Management of Cards and Components")
85    static int __devinit
86    snd_vortex_create(snd_card_t *card, struct pci_dev *pci, vortex_t **rchip) {
87        vortex_t *chip;
88        int err;
89        static snd_device_ops_t ops = {
90            .dev_free = snd_vortex_dev_free,
91        };
92    
93        *rchip = NULL;
94    
95        // check PCI availability (DMA).
96        if ((err = pci_enable_device(pci)) < 0)
97            return err;
98        if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) {
99            printk(KERN_ERR "error to set DMA mask\n");
100            return -ENXIO;
101        }
102        pci_set_dma_mask(pci, VORTEX_DMA_MASK);
103    
104        chip = snd_magic_kcalloc(vortex_t, 0, GFP_KERNEL);
105        if (chip == NULL)
106            return -ENOMEM;
107    
108        chip->card = card;
109    
110        // initialize the stuff
111        chip->pci_dev = pci;
112        chip->io = pci_resource_start(pci, 0);
113        chip->vendor = pci->vendor;
114        chip->device = pci->device;
115        chip->card = card;
116        chip->irq = -1;
117    
118        // (1) PCI resource allocation
119        // Get MMIO area
120        //
121        if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0)
122            goto regions_out;
123            
124        chip->mmio = ioremap_nocache(pci_resource_start(pci,0), pci_resource_len(pci,0));
125        if (!chip->mmio) {
126            printk(KERN_ERR "MMIO area remap failed.\n");
127            err = -ENOMEM;
128            goto ioremap_out;
129        }
130    
131        /* Init audio core.
132         * This must be done before we do request_irq otherwise we can get spurious
133         * interupts that we do not handle properly and make a mess of things */
134        if ((err = vortex_core_init(chip)) != 0) {
135            printk(KERN_ERR "hw core init failed\n");
136            goto core_out;
137        }
138        
139        if ((err = request_irq(pci->irq, vortex_interrupt, SA_INTERRUPT | SA_SHIRQ,
140                        CARD_NAME_SHORT, (void *) chip)) != 0) {
141            printk(KERN_ERR "cannot grab irq\n");
142            goto irq_out;
143        }
144        chip->irq = pci->irq;
145        
146        pci_set_master(pci);
147        // End of PCI setup.
148    
149    
150        // Register alsa root device.
151        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
152            goto alloc_out;
153        }
154    
155        *rchip = chip;
156    
157        return 0;
158        
159    alloc_out:
160        synchronize_irq(chip->irq);
161        free_irq(chip->irq, chip);
162    irq_out:
163        vortex_core_shutdown(chip);
164    core_out:
165        //FIXME: the type of chip->mmio might need to be changed??
166        iounmap((void*)chip->mmio);
167    ioremap_out:
168        pci_release_regions(chip->pci_dev);
169    regions_out:
170        pci_disable_device(chip->pci_dev);
171        //FIXME: this not the right place to unregister the gameport
172        vortex_gameport_unregister(chip);
173        return err;
174    }
175    
176    // constructor -- see "Constructor" sub-section
177    static int __devinit
178    snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) {
179        static int dev;
180        snd_card_t *card;
181        vortex_t *chip;
182        int err;
183    
184        // (1)
185        if (dev >= SNDRV_CARDS)
186            return -ENODEV;
187        if (!enable[dev]) {
188            dev++;
189            return -ENOENT;
190        }
191        // (2)
192        card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
193        if (card == NULL)
194            return -ENOMEM;
195    
196        // (3)
197        if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
198            snd_card_free(card);
199            return err;
200        }
201        // (4) Alloc components.
202        // ADB pcm.
203        if ((err = snd_vortex_new_pcm(chip, 0, NR_ADB)) < 0) {
204            snd_card_free(card);
205            return err;
206        }
207        // WT pcm.
208        if ((err = snd_vortex_new_pcm(chip, 1, NR_WT)) < 0) {
209            snd_card_free(card);
210            return err;
211        }
212        // snd_ac97_mixer and Vortex mixer.
213        if ((err = snd_vortex_mixer(chip)) < 0) {
214            snd_card_free(card);
215            return err;
216        }
217        if ((err = snd_vortex_midi(chip)) < 0) {
218            snd_card_free(card);
219            return err;
220        }
221        if ((err = vortex_gameport_register(chip)) < 0) {
222            snd_card_free(card);
223            return err;
224        }
225    #if 0
226        if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
227                               sizeof(snd_vortex_synth_arg_t), &wave) < 0
228            || wave == NULL) {
229            snd_printk("Can't initialize Aureal wavetable synth\n");
230        } else {
231            snd_vortex_synth_arg_t *arg;
232    
233            arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
234            strcpy(wave->name, "Aureal Synth");
235            arg->hwptr = vortex;
236            arg->index = 1;
237            arg->seq_ports = seq_ports[dev];
238            arg->max_voices = max_synth_voices[dev];
239        }
240    #endif
241    
242        // (5)
243        strcpy(card->driver, "Aureal Vortex");
244        strcpy(card->shortname, CARD_NAME_SHORT);
245        sprintf(card->longname, "%s at 0x%lx irq %i",
246                card->shortname, chip->io, chip->irq);
247        
248    #ifdef CHIP_AU8830
249        {
250            unsigned char revision;
251            if ((err = pci_read_config_byte(pci, PCI_REVISION_ID, &revision)) < 0) {
252                snd_card_free(card);
253                return err;
254            }
255    
256            if (revision != 0xfe && revision != 0xfa) {
257                printk(KERN_ALERT "vortex: The revision (%x) of your card has not been seen before.\n", revision);
258                printk(KERN_ALERT "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
259                snd_card_free(card);
260                err = -ENODEV;
261                return err;
262            }
263        }
264    #endif
265        // (6)
266        if ((err = snd_card_register(card)) < 0) {
267            snd_card_free(card);
268            return err;
269        }
270        // (7)
271        pci_set_drvdata(pci, chip);
272        dev++;
273        vortex_enable_int(chip);
274        return 0;
275    }
276    
277    // destructor -- see "Destructor" sub-section
278    static void __devexit snd_vortex_remove(struct pci_dev *pci) {
279        vortex_t *vortex = snd_magic_cast(vortex_t,
280                                          pci_get_drvdata(pci), return);
281    
282        if (vortex) {
283            // Release ALSA stuff.
284            snd_card_free(vortex->card);
285            // Free Vortex struct.
286            pci_set_drvdata(pci, NULL);
287        } else
288            printk("snd_vortex_remove called more than one time!\n");
289    }
290    
291    // pci_driver definition
292    static struct pci_driver driver = {
293        .name = CARD_NAME_SHORT,
294        .id_table = snd_vortex_ids,
295        .probe = snd_vortex_probe,
296        .remove = __devexit_p(snd_vortex_remove),
297    };
298    
299    // initialization of the module
300    static int __init alsa_card_vortex_init(void) {
301        int err;
302    
303        if ((err = pci_module_init(&driver)) < 0) {
304    #ifdef MODULE
305            printk(KERN_ERR "Aureal soundcard not found " "or device busy\n");
306    #endif
307            return err;
308        }
309        return 0;
310    }
311    
312    // clean up the module
313    static void __exit alsa_card_vortex_exit(void) {
314        pci_unregister_driver(&driver);
315    }
316    
317    module_init(alsa_card_vortex_init)
318    module_exit(alsa_card_vortex_exit)
319    
320    // for old kernels only
321    #ifdef EXPORT_NO_SYMBOLS
322    EXPORT_NO_SYMBOLS;
323    #endif

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26