⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gus_wave.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Envelope finished. Shoot the voice down */		gus_voice_init(voice);		return;	}	prev_vol = voices[voice].current_volume;	phase = ++voices[voice].env_phase;	compute_volume(voice, voices[voice].midi_volume);	vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;	rate = voices[voice].env_rate[phase];	save_flags(flags);	cli();	gus_select_voice(voice);	gus_voice_volume(prev_vol);	gus_write8(0x06, rate);	/* Ramping rate */	voices[voice].volume_irq_mode = VMODE_ENVELOPE;	if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */	{		restore_flags(flags);		step_envelope(voice);		/* Continue the envelope on the next step */		return;	}	if (vol > prev_vol)	{		if (vol >= (4096 - 64))			vol = 4096 - 65;		gus_ramp_range(0, vol);		gus_rampon(0x20);	/* Increasing volume, with IRQ */	}	else	{		if (vol <= 64)			vol = 65;		gus_ramp_range(vol, 4030);		gus_rampon(0x60);	/* Decreasing volume, with IRQ */	}	voices[voice].current_volume = vol;	restore_flags(flags);}static void init_envelope(int voice){	voices[voice].env_phase = -1;	voices[voice].current_volume = 64;	step_envelope(voice);}static void start_release(int voice, long int flags){	if (gus_read8(0x00) & 0x03)		return;		/* Voice already stopped */	voices[voice].env_phase = 2;	/* Will be incremented by step_envelope */	voices[voice].current_volume = voices[voice].initial_volume =						gus_read16(0x09) >> 4;	/* Get current volume */	voices[voice].mode &= ~WAVE_SUSTAIN_ON;	gus_rampoff();	restore_flags(flags);	step_envelope(voice);}static void gus_voice_fade(int voice){	int instr_no = sample_map[voice], is16bits;	long int flags;	save_flags(flags);	cli();	gus_select_voice(voice);	if (instr_no < 0 || instr_no > MAX_SAMPLE)	{		gus_write8(0x00, 0x03);	/* Hard stop */		voice_alloc->map[voice] = 0;		restore_flags(flags);		return;	}	is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */	if (voices[voice].mode & WAVE_ENVELOPES)	{		start_release(voice, flags);		restore_flags(flags);		return;	}	/*	 * Ramp the volume down but not too quickly.	 */	if ((int) (gus_read16(0x09) >> 4) < 100)	/* Get current volume */	{		gus_voice_off();		gus_rampoff();		gus_voice_init(voice);		restore_flags(flags);		return;	}	gus_ramp_range(65, 4030);	gus_ramp_rate(2, 4);	gus_rampon(0x40 | 0x20);	/* Down, once, with IRQ */	voices[voice].volume_irq_mode = VMODE_HALT;	restore_flags(flags);}static void gus_reset(void){	int i;	gus_select_max_voices(24);	volume_base = 3071;	volume_scale = 4;	volume_method = VOL_METHOD_ADAGIO;	for (i = 0; i < 32; i++)	{		gus_voice_init(i);	/* Turn voice off */		gus_voice_init2(i);	}}static void gus_initialize(void){	unsigned long flags;	unsigned char dma_image, irq_image, tmp;	static unsigned char gus_irq_map[16] = 	{		0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7	};	static unsigned char gus_dma_map[8] = {		0, 1, 0, 2, 0, 3, 4, 5	};	save_flags(flags);	cli();	gus_write8(0x4c, 0);	/* Reset GF1 */	gus_delay();	gus_delay();	gus_write8(0x4c, 1);	/* Release Reset */	gus_delay();	gus_delay();	/*	 * Clear all interrupts	 */	gus_write8(0x41, 0);	/* DMA control */	gus_write8(0x45, 0);	/* Timer control */	gus_write8(0x49, 0);	/* Sample control */	gus_select_max_voices(24);	inb(u_Status);		/* Touch the status register */	gus_look8(0x41);	/* Clear any pending DMA IRQs */	gus_look8(0x49);	/* Clear any pending sample IRQs */	gus_read8(0x0f);	/* Clear pending IRQs */	gus_reset();		/* Resets all voices */	gus_look8(0x41);	/* Clear any pending DMA IRQs */	gus_look8(0x49);	/* Clear any pending sample IRQs */	gus_read8(0x0f);	/* Clear pending IRQs */	gus_write8(0x4c, 7);	/* Master reset | DAC enable | IRQ enable */	/*	 * Set up for Digital ASIC	 */	outb((0x05), gus_base + 0x0f);	mix_image |= 0x02;	/* Disable line out (for a moment) */	outb((mix_image), u_Mixer);	outb((0x00), u_IRQDMAControl);	outb((0x00), gus_base + 0x0f);	/*	 * Now set up the DMA and IRQ interface	 *	 * The GUS supports two IRQs and two DMAs.	 *	 * Just one DMA channel is used. This prevents simultaneous ADC and DAC.	 * Adding this support requires significant changes to the dmabuf.c, dsp.c	 * and audio.c also.	 */	irq_image = 0;	tmp = gus_irq_map[gus_irq];	if (!gus_pnp_flag && !tmp)		printk(KERN_WARNING "Warning! GUS IRQ not selected\n");	irq_image |= tmp;	irq_image |= 0x40;	/* Combine IRQ1 (GF1) and IRQ2 (Midi) */	dual_dma_mode = 1;	if (gus_dma2 == gus_dma || gus_dma2 == -1)	{		dual_dma_mode = 0;		dma_image = 0x40;	/* Combine DMA1 (DRAM) and IRQ2 (ADC) */		tmp = gus_dma_map[gus_dma];		if (!tmp)			printk(KERN_WARNING "Warning! GUS DMA not selected\n");		dma_image |= tmp;	}	else	{		/* Setup dual DMA channel mode for GUS MAX */		dma_image = gus_dma_map[gus_dma];		if (!dma_image)			printk(KERN_WARNING "Warning! GUS DMA not selected\n");		tmp = gus_dma_map[gus_dma2] << 3;		if (!tmp)		{			printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");			tmp = 0x40;		/* Combine DMA channels */			    dual_dma_mode = 0;		}		dma_image |= tmp;	}	/*	 * For some reason the IRQ and DMA addresses must be written twice	 */	/*	 * Doing it first time	 */	outb((mix_image), u_Mixer);	/* Select DMA control */	outb((dma_image | 0x80), u_IRQDMAControl);	/* Set DMA address */	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */	/*	 * Doing it second time	 */	outb((mix_image), u_Mixer);	/* Select DMA control */	outb((dma_image), u_IRQDMAControl);	/* Set DMA address */	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */	mix_image &= ~0x02;	/* Enable line out */	mix_image |= 0x08;	/* Enable IRQ */	outb((mix_image), u_Mixer);	/*					 * Turn mixer channels on					 * Note! Mic in is left off.					 */	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */	inb(u_Status);		/* Touch the status register */	gus_look8(0x41);	/* Clear any pending DMA IRQs */	gus_look8(0x49);	/* Clear any pending sample IRQs */	gus_read8(0x0f);	/* Clear pending IRQs */	if (iw_mode)		gus_write8(0x19, gus_read8(0x19) | 0x01);	restore_flags(flags);}static void __init pnp_mem_init(void){#include "iwmem.h"#define CHUNK_SIZE (256*1024)#define BANK_SIZE (4*1024*1024)#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)	int bank, chunk, addr, total = 0;	int bank_sizes[4];	int i, j, bits = -1, testbits = -1, nbanks = 0;	/*	 * This routine determines what kind of RAM is installed in each of the four	 * SIMM banks and configures the DRAM address decode logic accordingly.	 */	/*	 *    Place the chip into enhanced mode	 */	gus_write8(0x19, gus_read8(0x19) | 0x01);	gus_write8(0x53, gus_look8(0x53) & ~0x02);	/* Select DRAM I/O access */	/*	 * Set memory configuration to 4 DRAM banks of 4M in each (16M total).	 */	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);	/*	 * Perform the DRAM size detection for each bank individually.	 */	for (bank = 0; bank < 4; bank++)	{		int size = 0;		addr = bank * BANK_SIZE;		/* Clean check points of each chunk */		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)		{			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);		}		/* Write a value to each chunk point and verify the result */		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)		{			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);			if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&				gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)			{				/* OK. There is RAM. Now check for possible shadows */				int ok = 1, chunk2;				for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)					if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||							gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))						ok = 0;	/* Addressing wraps */				if (ok)					size = (chunk + 1) * CHUNK_SIZE;			}			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);		}		bank_sizes[bank] = size;		if (size)			nbanks = bank + 1;		DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));	}	if (nbanks == 0)	/* No RAM - Give up */	{		printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");		printk(KERN_ERR "Sound: Unable to work with this card.\n");		gus_write8(0x19, gus_read8(0x19) & ~0x01);		gus_mem_size = 0;		return;	}	/*	 * Now we know how much DRAM there is in each bank. The next step is	 * to find a DRAM size encoding (0 to 12) which is best for the combination	 * we have.	 *	 * First try if any of the possible alternatives matches exactly the amount	 * of memory we have.	 */	for (i = 0; bits == -1 && i < 13; i++)	{		bits = i;		for (j = 0; bits != -1 && j < 4; j++)			if (mem_decode[i][j] != bank_sizes[j])				bits = -1;	/* No hit */	}	/*	 * If necessary, try to find a combination where other than the last	 * bank matches our configuration and the last bank is left oversized.	 * In this way we don't leave holes in the middle of memory.	 */	if (bits == -1)		/* No luck yet */	{		for (i = 0; bits == -1 && i < 13; i++)		{			bits = i;			for (j = 0; bits != -1 && j < nbanks - 1; j++)				if (mem_decode[i][j] != bank_sizes[j])					bits = -1;	/* No hit */			if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])				bits = -1;	/* The last bank is too small */		}	}	/* 	 * The last resort is to search for a combination where the banks are 	 * smaller than the actual SIMMs. This leaves some memory in the banks 	 * unused but doesn't leave holes in the DRAM address space. 	 */ 	if (bits == -1)		/* No luck yet */ 	{ 		for (i = 0; i < 13; i++) 		{ 			testbits = i; 			for (j = 0; testbits != -1 && j < nbanks - 1; j++) 				if (mem_decode[i][j] > bank_sizes[j]) { 					testbits = -1; 				} 			if(testbits > bits) bits = testbits; 		} 		if (bits != -1) 		{			printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");			printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");		}		printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");		printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");		bits = 0;	}	DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));	for (bank = 0; bank < 4; bank++)	{		DDB(printk("  Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));		if (bank_sizes[bank] > mem_decode[bits][bank])			total += mem_decode[bits][bank];		else			total += bank_sizes[bank];	}	DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));	/*	 *    Set the memory addressing mode.	 */	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);/*      Leave the chip into enhanced mode. Disable LFO  */	gus_mem_size = total;	iw_mode = 1;	gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);}int __init gus_wave_detect(int baseaddr){	unsigned long   i, max_mem = 1024L;	unsigned long   loc;	unsigned char   val;	gus_base = baseaddr;	gus_write8(0x4c, 0);	/* Reset GF1 */	gus_delay();	gus_delay();	gus_write8(0x4c, 1);	/* Release Reset */	gus_delay();	gus_delay();#ifdef GUSPNP_AUTODETECT	val = gus_look8(0x5b);	/* Version number register */	gus_write8(0x5b, ~val);	/* Invert all bits */	if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0))	/* No change */	{		if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f))	/* Change */		{			DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));			gus_pnp_flag = 1;		}		else		{			DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));			gus_pnp_flag = 0;		}	}	gus_write8(0x5b, val);	/* Restore all bits */#endif	if (gus_pnp_flag)		pnp_mem_init();	if (iw_mode)		return 1;	/* See if there is first block there.... */	gus_poke(0L, 0xaa);	if (gus_peek(0L) != 0xaa)		return (0);	/* Now zero it out so that I can check for mirroring .. */	gus_poke(0L, 0x00);	for (i = 1L; i < max_mem; i++)	{		int n, failed;		/* check for mirroring ... */		if (gus_peek(0L) != 0)			break;		loc = i << 10;		for (n = loc - 1, failed = 0; n <= loc; n++)		{			gus_poke(loc, 0xaa);			if (gus_peek(loc) != 0xaa)				failed = 1;			gus_poke(loc, 0x55);			if (gus_peek(loc) != 0x55)				failed = 1;		}		if (failed)			break;	}	gus_mem_size = i << 10;	return 1;}static int guswave_ioctl(int dev, unsigned int cmd, caddr_t arg){	switch (cmd) 	{		case SNDCTL_SYNTH_INFO:			gus_info.nr_voices = nr_voices;			if (copy_to_user(arg, &gus_info, sizeof(gus_info)))				return -EFAULT;			return 0;		case SNDCTL_SEQ_RESETSAMPLES:			reset_sample_memory();			return 0;		case SNDCTL_SEQ_PERCMODE:			return 0;		case SNDCTL_SYNTH_MEMAVL:			return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;		default:			return -EINVAL;	}}static int guswave_set_instr(int dev, int voice, int instr_no){	int sample_no;	if (instr_no < 0 || instr_no > MAX_PATCH)		instr_no = 0;	/* Default to acoustic piano */	if (voice < 0 || voice > 31)		return -EINVAL;	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)	{		voices[voice].sample_pending = instr_no;		return 0;	}	sample_no = patch_table[instr_no];	patch_map[voice] = -1;	if (sample_no == NOT_SAMPLE)	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -