| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * sound/gus_card.c | 
 | 3 |  * | 
 | 4 |  * Detection routine for the Gravis Ultrasound. | 
 | 5 |  * | 
 | 6 |  * Copyright (C) by Hannu Savolainen 1993-1997 | 
 | 7 |  * | 
 | 8 |  * | 
 | 9 |  * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious | 
 | 10 |  *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX. | 
 | 11 |  * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups. | 
 | 12 |  * | 
 | 13 |  * Status: | 
 | 14 |  *              Tested...  | 
 | 15 |  */ | 
 | 16 |        | 
 | 17 |   | 
 | 18 | #include <linux/config.h> | 
 | 19 | #include <linux/init.h> | 
 | 20 | #include <linux/interrupt.h> | 
 | 21 | #include <linux/module.h> | 
 | 22 |  | 
 | 23 | #include "sound_config.h" | 
 | 24 |  | 
 | 25 | #include "gus.h" | 
 | 26 | #include "gus_hw.h" | 
 | 27 |  | 
 | 28 | irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy); | 
 | 29 |  | 
 | 30 | int             gus_base = 0, gus_irq = 0, gus_dma = 0; | 
 | 31 | int             gus_no_wave_dma = 0;  | 
 | 32 | extern int      gus_wave_volume; | 
 | 33 | extern int      gus_pcm_volume; | 
 | 34 | extern int      have_gus_max; | 
 | 35 | int             gus_pnp_flag = 0; | 
 | 36 | #ifdef CONFIG_SOUND_GUS16 | 
 | 37 | static int      db16;	/* Has a Gus16 AD1848 on it */ | 
 | 38 | #endif | 
 | 39 |  | 
 | 40 | static void __init attach_gus(struct address_info *hw_config) | 
 | 41 | { | 
 | 42 | 	gus_wave_init(hw_config); | 
 | 43 |  | 
 | 44 | 	if (sound_alloc_dma(hw_config->dma, "GUS")) | 
 | 45 | 		printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma); | 
 | 46 | 	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) | 
 | 47 | 		if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) | 
 | 48 | 			printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); | 
 | 49 | 	gus_midi_init(hw_config); | 
 | 50 | 	if(request_irq(hw_config->irq, gusintr, 0,  "Gravis Ultrasound", hw_config)<0) | 
 | 51 | 		printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); | 
 | 52 |  | 
 | 53 | 	return; | 
 | 54 | } | 
 | 55 |  | 
 | 56 | static int __init probe_gus(struct address_info *hw_config) | 
 | 57 | { | 
 | 58 | 	int             irq; | 
 | 59 | 	int             io_addr; | 
 | 60 |  | 
 | 61 | 	if (hw_config->card_subtype == 1) | 
 | 62 | 		gus_pnp_flag = 1; | 
 | 63 |  | 
 | 64 | 	irq = hw_config->irq; | 
 | 65 |  | 
 | 66 | 	if (hw_config->card_subtype == 0)	/* GUS/MAX/ACE */ | 
 | 67 | 		if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && | 
 | 68 | 		    irq != 11 && irq != 12 && irq != 15) | 
 | 69 | 		  { | 
 | 70 | 			  printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq); | 
 | 71 | 			  return 0; | 
 | 72 | 		  } | 
 | 73 | 	if (gus_wave_detect(hw_config->io_base)) | 
 | 74 | 		return 1; | 
 | 75 |  | 
 | 76 | #ifndef EXCLUDE_GUS_IODETECT | 
 | 77 |  | 
 | 78 | 	/* | 
 | 79 | 	 * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) | 
 | 80 | 	 */ | 
 | 81 |  | 
 | 82 | 	for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) { | 
 | 83 | 		if (io_addr == hw_config->io_base)	/* Already tested */ | 
 | 84 | 			continue; | 
 | 85 | 		if (gus_wave_detect(io_addr)) { | 
 | 86 | 			hw_config->io_base = io_addr; | 
 | 87 | 			return 1; | 
 | 88 | 		} | 
 | 89 | 	} | 
 | 90 | #endif | 
 | 91 |  | 
 | 92 | 	printk("NO GUS card found !\n"); | 
 | 93 | 	return 0; | 
 | 94 | } | 
 | 95 |  | 
 | 96 | static void __exit unload_gus(struct address_info *hw_config) | 
 | 97 | { | 
 | 98 | 	DDB(printk("unload_gus(%x)\n", hw_config->io_base)); | 
 | 99 |  | 
 | 100 | 	gus_wave_unload(hw_config); | 
 | 101 |  | 
 | 102 | 	release_region(hw_config->io_base, 16); | 
 | 103 | 	release_region(hw_config->io_base + 0x100, 12);		/* 0x10c-> is MAX */ | 
 | 104 | 	free_irq(hw_config->irq, hw_config); | 
 | 105 |  | 
 | 106 | 	sound_free_dma(hw_config->dma); | 
 | 107 |  | 
 | 108 | 	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) | 
 | 109 | 		sound_free_dma(hw_config->dma2); | 
 | 110 | } | 
 | 111 |  | 
 | 112 | irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy) | 
 | 113 | { | 
 | 114 | 	unsigned char src; | 
 | 115 | 	extern int gus_timer_enabled; | 
 | 116 | 	int handled = 0; | 
 | 117 |  | 
 | 118 | #ifdef CONFIG_SOUND_GUSMAX | 
 | 119 | 	if (have_gus_max) { | 
 | 120 | 		struct address_info *hw_config = dev_id; | 
 | 121 | 		adintr(irq, (void *)hw_config->slots[1], NULL); | 
 | 122 | 	} | 
 | 123 | #endif | 
 | 124 | #ifdef CONFIG_SOUND_GUS16 | 
 | 125 | 	if (db16) { | 
 | 126 | 		struct address_info *hw_config = dev_id; | 
 | 127 | 		adintr(irq, (void *)hw_config->slots[3], NULL); | 
 | 128 | 	} | 
 | 129 | #endif | 
 | 130 |  | 
 | 131 | 	while (1) | 
 | 132 | 	{ | 
 | 133 | 		if (!(src = inb(u_IrqStatus))) | 
 | 134 | 			break; | 
 | 135 | 		handled = 1; | 
 | 136 | 		if (src & DMA_TC_IRQ) | 
 | 137 | 		{ | 
 | 138 | 			guswave_dma_irq(); | 
 | 139 | 		} | 
 | 140 | 		if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) | 
 | 141 | 		{ | 
 | 142 | 			gus_midi_interrupt(0); | 
 | 143 | 		} | 
 | 144 | 		if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) | 
 | 145 | 		{ | 
 | 146 | 			if (gus_timer_enabled) | 
 | 147 | 				sound_timer_interrupt(); | 
 | 148 | 			gus_write8(0x45, 0);	/* Ack IRQ */ | 
 | 149 | 			gus_timer_command(4, 0x80);		/* Reset IRQ flags */ | 
 | 150 | 		} | 
 | 151 | 		if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) | 
 | 152 | 			gus_voice_irq(); | 
 | 153 | 	} | 
 | 154 | 	return IRQ_RETVAL(handled); | 
 | 155 | } | 
 | 156 |  | 
 | 157 | /* | 
 | 158 |  *	Some extra code for the 16 bit sampling option | 
 | 159 |  */ | 
 | 160 |  | 
 | 161 | #ifdef CONFIG_SOUND_GUS16 | 
 | 162 |  | 
 | 163 | static int __init init_gus_db16(struct address_info *hw_config) | 
 | 164 | { | 
 | 165 | 	struct resource *ports; | 
 | 166 |  | 
 | 167 | 	ports = request_region(hw_config->io_base, 4, "ad1848"); | 
 | 168 | 	if (!ports) | 
 | 169 | 		return 0; | 
 | 170 |  | 
 | 171 | 	if (!ad1848_detect(ports, NULL, hw_config->osp)) { | 
 | 172 | 		release_region(hw_config->io_base, 4); | 
 | 173 | 		return 0; | 
 | 174 | 	} | 
 | 175 |  | 
 | 176 | 	gus_pcm_volume = 100; | 
 | 177 | 	gus_wave_volume = 90; | 
 | 178 |  | 
 | 179 | 	hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports, | 
 | 180 | 					  hw_config->irq, | 
 | 181 | 					  hw_config->dma, | 
 | 182 | 					  hw_config->dma, 0, | 
 | 183 | 					  hw_config->osp, | 
 | 184 | 					  THIS_MODULE); | 
 | 185 | 	return 1; | 
 | 186 | } | 
 | 187 |  | 
 | 188 | static void __exit unload_gus_db16(struct address_info *hw_config) | 
 | 189 | { | 
 | 190 |  | 
 | 191 | 	ad1848_unload(hw_config->io_base, | 
 | 192 | 		      hw_config->irq, | 
 | 193 | 		      hw_config->dma, | 
 | 194 | 		      hw_config->dma, 0); | 
 | 195 | 	sound_unload_audiodev(hw_config->slots[3]); | 
 | 196 | } | 
 | 197 | #endif | 
 | 198 |  | 
 | 199 | #ifdef CONFIG_SOUND_GUS16 | 
 | 200 | static int gus16; | 
 | 201 | #endif | 
 | 202 | #ifdef CONFIG_SOUND_GUSMAX | 
 | 203 | static int no_wave_dma;   /* Set if no dma is to be used for the | 
 | 204 |                                    wave table (GF1 chip) */ | 
 | 205 | #endif | 
 | 206 |  | 
 | 207 |  | 
 | 208 | /* | 
 | 209 |  *    Note DMA2 of -1 has the right meaning in the GUS driver as well | 
 | 210 |  *      as here.  | 
 | 211 |  */ | 
 | 212 |  | 
 | 213 | static struct address_info cfg; | 
 | 214 |  | 
 | 215 | static int __initdata io = -1; | 
 | 216 | static int __initdata irq = -1; | 
 | 217 | static int __initdata dma = -1; | 
 | 218 | static int __initdata dma16 = -1;	/* Set this for modules that need it */ | 
 | 219 | static int __initdata type = 0;		/* 1 for PnP */ | 
 | 220 |  | 
 | 221 | module_param(io, int, 0); | 
 | 222 | module_param(irq, int, 0); | 
 | 223 | module_param(dma, int, 0); | 
 | 224 | module_param(dma16, int, 0); | 
 | 225 | module_param(type, int, 0); | 
 | 226 | #ifdef CONFIG_SOUND_GUSMAX | 
 | 227 | module_param(no_wave_dma, int, 0); | 
 | 228 | #endif | 
 | 229 | #ifdef CONFIG_SOUND_GUS16 | 
 | 230 | module_param(db16, int, 0); | 
 | 231 | module_param(gus16, int, 0); | 
 | 232 | #endif | 
 | 233 | MODULE_LICENSE("GPL"); | 
 | 234 |  | 
 | 235 | static int __init init_gus(void) | 
 | 236 | { | 
 | 237 | 	printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); | 
 | 238 |  | 
 | 239 | 	cfg.io_base = io; | 
 | 240 | 	cfg.irq = irq; | 
 | 241 | 	cfg.dma = dma; | 
 | 242 | 	cfg.dma2 = dma16; | 
 | 243 | 	cfg.card_subtype = type; | 
 | 244 | #ifdef CONFIG_SOUND_GUSMAX | 
 | 245 | 	gus_no_wave_dma = no_wave_dma; | 
 | 246 | #endif | 
 | 247 |  | 
 | 248 | 	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { | 
 | 249 | 		printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); | 
 | 250 | 		return -EINVAL; | 
 | 251 | 	} | 
 | 252 |  | 
 | 253 | #ifdef CONFIG_SOUND_GUS16 | 
 | 254 | 	if (gus16 && init_gus_db16(&cfg)) | 
 | 255 | 		db16 = 1; | 
 | 256 | #endif | 
 | 257 | 	if (!probe_gus(&cfg)) | 
 | 258 | 		return -ENODEV; | 
 | 259 | 	attach_gus(&cfg); | 
 | 260 |  | 
 | 261 | 	return 0; | 
 | 262 | } | 
 | 263 |  | 
 | 264 | static void __exit cleanup_gus(void) | 
 | 265 | { | 
 | 266 | #ifdef CONFIG_SOUND_GUS16 | 
 | 267 | 	if (db16) | 
 | 268 | 		unload_gus_db16(&cfg); | 
 | 269 | #endif | 
 | 270 | 	unload_gus(&cfg); | 
 | 271 | } | 
 | 272 |  | 
 | 273 | module_init(init_gus); | 
 | 274 | module_exit(cleanup_gus); | 
 | 275 |  | 
 | 276 | #ifndef MODULE | 
 | 277 | static int __init setup_gus(char *str) | 
 | 278 | { | 
 | 279 | 	/* io, irq, dma, dma2 */ | 
 | 280 | 	int ints[5]; | 
 | 281 | 	 | 
 | 282 | 	str = get_options(str, ARRAY_SIZE(ints), ints); | 
 | 283 | 	 | 
 | 284 | 	io	= ints[1]; | 
 | 285 | 	irq	= ints[2]; | 
 | 286 | 	dma	= ints[3]; | 
 | 287 | 	dma16	= ints[4]; | 
 | 288 |  | 
 | 289 | 	return 1; | 
 | 290 | } | 
 | 291 |  | 
 | 292 | __setup("gus=", setup_gus); | 
 | 293 | #endif |