/* * sound/gus_card.c * * Detection routine for the Gravis Ultrasound. * * Copyright (C) by Hannu Savolainen 1993-1997 * * * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups. * * Status: * Tested... */ #include #include #include #include #include "sound_config.h" #include "gus.h" #include "gus_hw.h" irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy); int gus_base = 0, gus_irq = 0, gus_dma = 0; int gus_no_wave_dma = 0; extern int gus_wave_volume; extern int gus_pcm_volume; extern int have_gus_max; int gus_pnp_flag = 0; #ifdef CONFIG_SOUND_GUS16 static int db16; /* Has a Gus16 AD1848 on it */ #endif static void __init attach_gus(struct address_info *hw_config) { gus_wave_init(hw_config); if (sound_alloc_dma(hw_config->dma, "GUS")) printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma); if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); gus_midi_init(hw_config); if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); return; } static int __init probe_gus(struct address_info *hw_config) { int irq; int io_addr; if (hw_config->card_subtype == 1) gus_pnp_flag = 1; irq = hw_config->irq; if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && irq != 11 && irq != 12 && irq != 15) { printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq); return 0; } if (gus_wave_detect(hw_config->io_base)) return 1; #ifndef EXCLUDE_GUS_IODETECT /* * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) */ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) { if (io_addr == hw_config->io_base) /* Already tested */ continue; if (gus_wave_detect(io_addr)) { hw_config->io_base = io_addr; return 1; } } #endif printk("NO GUS card found !\n"); return 0; } static void __exit unload_gus(struct address_info *hw_config) { DDB(printk("unload_gus(%x)\n", hw_config->io_base)); gus_wave_unload(hw_config); release_region(hw_config->io_base, 16); release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ free_irq(hw_config->irq, hw_config); sound_free_dma(hw_config->dma); if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) sound_free_dma(hw_config->dma2); } irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy) { unsigned char src; extern int gus_timer_enabled; int handled = 0; #ifdef CONFIG_SOUND_GUSMAX if (have_gus_max) { struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[1], NULL); } #endif #ifdef CONFIG_SOUND_GUS16 if (db16) { struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[3], NULL); } #endif while (1) { if (!(src = inb(u_IrqStatus))) break; handled = 1; if (src & DMA_TC_IRQ) { guswave_dma_irq(); } if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) { gus_midi_interrupt(0); } if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { if (gus_timer_enabled) sound_timer_interrupt(); gus_write8(0x45, 0); /* Ack IRQ */ gus_timer_command(4, 0x80); /* Reset IRQ flags */ } if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) gus_voice_irq(); } return IRQ_RETVAL(handled); } /* * Some extra code for the 16 bit sampling option */ #ifdef CONFIG_SOUND_GUS16 static int __init init_gus_db16(struct address_info *hw_config) { struct resource *ports; ports = request_region(hw_config->io_base, 4, "ad1848"); if (!ports) return 0; if (!ad1848_detect(ports, NULL, hw_config->osp)) { release_region(hw_config->io_base, 4); return 0; } gus_pcm_volume = 100; gus_wave_volume = 90; hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports, hw_config->irq, hw_config->dma, hw_config->dma, 0, hw_config->osp, THIS_MODULE); return 1; } static void __exit unload_gus_db16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma, 0); sound_unload_audiodev(hw_config->slots[3]); } #endif #ifdef CONFIG_SOUND_GUS16 static int gus16; #endif #ifdef CONFIG_SOUND_GUSMAX static int no_wave_dma; /* Set if no dma is to be used for the wave table (GF1 chip) */ #endif /* * Note DMA2 of -1 has the right meaning in the GUS driver as well * as here. */ static struct address_info cfg; static int __initdata io = -1; static int __initdata irq = -1; static int __initdata dma = -1; static int __initdata dma16 = -1; /* Set this for modules that need it */ static int __initdata type = 0; /* 1 for PnP */ module_param(io, int, 0); module_param(irq, int, 0); module_param(dma, int, 0); module_param(dma16, int, 0); module_param(type, int, 0); #ifdef CONFIG_SOUND_GUSMAX module_param(no_wave_dma, int, 0); #endif #ifdef CONFIG_SOUND_GUS16 module_param(db16, int, 0); module_param(gus16, int, 0); #endif MODULE_LICENSE("GPL"); static int __init init_gus(void) { printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; cfg.dma2 = dma16; cfg.card_subtype = type; #ifdef CONFIG_SOUND_GUSMAX gus_no_wave_dma = no_wave_dma; #endif if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } #ifdef CONFIG_SOUND_GUS16 if (gus16 && init_gus_db16(&cfg)) db16 = 1; #endif if (!probe_gus(&cfg)) return -ENODEV; attach_gus(&cfg); return 0; } static void __exit cleanup_gus(void) { #ifdef CONFIG_SOUND_GUS16 if (db16) unload_gus_db16(&cfg); #endif unload_gus(&cfg); } module_init(init_gus); module_exit(cleanup_gus); #ifndef MODULE static int __init setup_gus(char *str) { /* io, irq, dma, dma2 */ int ints[5]; str = get_options(str, ARRAY_SIZE(ints), ints); io = ints[1]; irq = ints[2]; dma = ints[3]; dma16 = ints[4]; return 1; } __setup("gus=", setup_gus); #endif