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

📄 gus_wave.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * Copy the header from user space but ignore the first bytes which have	 * been transferred already.	 */	copy_from_user(&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs);	if (patch.mode & WAVE_ROM)		return -EINVAL;	if (gus_mem_size == 0)		return -ENOSPC;	instr = patch.instr_no;	if (instr < 0 || instr > MAX_PATCH)	{/*		printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/		return -EINVAL;	}	if (count < patch.len)	{/*		printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/		patch.len = count;	}	if (patch.len <= 0 || patch.len > gus_mem_size)	{/*		printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/		return -EINVAL;	}	if (patch.mode & WAVE_LOOPING)	{		if (patch.loop_start < 0 || patch.loop_start >= patch.len)		{/*			printk(KERN_ERR "GUS: Invalid loop start\n");*/			return -EINVAL;		}		if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)		{/*			printk(KERN_ERR "GUS: Invalid loop end\n");*/			return -EINVAL;		}	}	free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 32 byte alignment */	if (patch.mode & WAVE_16_BITS)	{		/*		 * 16 bit samples must fit one 256k bank.		 */		if (patch.len >= GUS_BANK_SIZE)		{/*			 printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/			return -ENOSPC;		}		if ((free_mem_ptr / GUS_BANK_SIZE) !=			((free_mem_ptr + patch.len) / GUS_BANK_SIZE))		{			unsigned long   tmp_mem =					/* Align to 256K */					((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;			if ((tmp_mem + patch.len) > gus_mem_size)				return -ENOSPC;			free_mem_ptr = tmp_mem;		/* This leaves unusable memory */		}	}	if ((free_mem_ptr + patch.len) > gus_mem_size)		return -ENOSPC;	sample_ptrs[free_sample] = free_mem_ptr;	/*	 * Tremolo is not possible with envelopes	 */	if (patch.mode & WAVE_ENVELOPES)		patch.mode &= ~WAVE_TREMOLO;	if (!(patch.mode & WAVE_FRACTIONS))	{		  patch.fractions = 0;	}	memcpy((char *) &samples[free_sample], &patch, sizeof_patch);	/*	 * Link this_one sample to the list of samples for patch 'instr'.	 */	samples[free_sample].key = patch_table[instr];	patch_table[instr] = free_sample;	/*	 * Use DMA to transfer the wave data to the DRAM	 */	left = patch.len;	src_offs = 0;	target = free_mem_ptr;	while (left)		/* Not completely transferred yet */	{		blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;		if (blk_sz > left)			blk_sz = left;		/*		 * DMA cannot cross bank (256k) boundaries. Check for that.		 */		 		blk_end = target + blk_sz;		if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))		{			/* Split the block */			blk_end &= ~(GUS_BANK_SIZE - 1);			blk_sz = blk_end - target;		}		if (gus_no_dma)		{			/*			 * For some reason the DMA is not possible. We have to use PIO.			 */			long i;			unsigned char data;			for (i = 0; i < blk_sz; i++)			{				get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i]));				if (patch.mode & WAVE_UNSIGNED)					if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))						data ^= 0x80;	/* Convert to signed */				gus_poke(target + i, data);			}		}		else		{			unsigned long address, hold_address;			unsigned char dma_command;			unsigned long flags;			if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)			{				printk(KERN_ERR "GUS: DMA buffer == NULL\n");				return -ENOSPC;			}			/*			 * OK, move now. First in and then out.			 */			copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz);			save_flags(flags);			cli();			/******** INTERRUPTS DISABLED NOW ********/			gus_write8(0x41, 0);	/* Disable GF1 DMA */			DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,				blk_sz, DMA_MODE_WRITE);			/*			 * Set the DRAM address for the wave data			 */			if (iw_mode)			{				/* Different address translation in enhanced mode */				unsigned char   hi;				if (gus_dma > 4)					address = target >> 1;	/* Convert to 16 bit word address */				else					address = target;				hi = (unsigned char) ((address >> 16) & 0xf0);				hi += (unsigned char) (address & 0x0f);				gus_write16(0x42, (address >> 4) & 0xffff);	/* DMA address (low) */				gus_write8(0x50, hi);			}			else			{				address = target;				if (audio_devs[gus_devnum]->dmap_out->dma > 3)				{					hold_address = address;					address = address >> 1;					address &= 0x0001ffffL;					address |= (hold_address & 0x000c0000L);				}				gus_write16(0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */			}			/*			 * Start the DMA transfer			 */			dma_command = 0x21;		/* IRQ enable, DMA start */			if (patch.mode & WAVE_UNSIGNED)				dma_command |= 0x80;	/* Invert MSB */			if (patch.mode & WAVE_16_BITS)				dma_command |= 0x40;	/* 16 bit _DATA_ */			if (audio_devs[gus_devnum]->dmap_out->dma > 3)				dma_command |= 0x04;	/* 16 bit DMA _channel_ */						gus_write8(0x41, dma_command);	/* Lets go luteet (=bugs) */			/*			 * Sleep here until the DRAM DMA done interrupt is served			 */			active_device = GUS_DEV_WAVE;			if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))				printk("GUS: DMA Transfer timed out\n");			restore_flags(flags);		}		/*		 * Now the next part		 */		left -= blk_sz;		src_offs += blk_sz;		target += blk_sz;		gus_write8(0x41, 0);	/* Stop DMA */	}	free_mem_ptr += patch.len;	free_sample++;	return 0;}static void guswave_hw_control(int dev, unsigned char *event_rec){	int voice, cmd;	unsigned short p1, p2;	unsigned int plong;	unsigned flags;	cmd = event_rec[2];	voice = event_rec[3];	p1 = *(unsigned short *) &event_rec[4];	p2 = *(unsigned short *) &event_rec[6];	plong = *(unsigned int *) &event_rec[4];	if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&		(cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))		do_volume_irq(voice);	switch (cmd)	{		case _GUS_NUMVOICES:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_select_max_voices(p1);			restore_flags(flags);			break;		case _GUS_VOICESAMPLE:			guswave_set_instr(dev, voice, p1);			break;		case _GUS_VOICEON:			save_flags(flags);			cli();			gus_select_voice(voice);			p1 &= ~0x20;	/* Don't allow interrupts */			gus_voice_on(p1);			restore_flags(flags);			break;		case _GUS_VOICEOFF:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_voice_off();			restore_flags(flags);			break;		case _GUS_VOICEFADE:			gus_voice_fade(voice);			break;		case _GUS_VOICEMODE:			save_flags(flags);			cli();			gus_select_voice(voice);			p1 &= ~0x20;	/* Don't allow interrupts */			gus_voice_mode(p1);			restore_flags(flags);			break;		case _GUS_VOICEBALA:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_voice_balance(p1);			restore_flags(flags);			break;		case _GUS_VOICEFREQ:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_voice_freq(plong);			restore_flags(flags);			break;		case _GUS_VOICEVOL:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_voice_volume(p1);			restore_flags(flags);			break;		case _GUS_VOICEVOL2:	/* Just update the software voice level */			voices[voice].initial_volume = voices[voice].current_volume = p1;			break;		case _GUS_RAMPRANGE:			if (voices[voice].mode & WAVE_ENVELOPES)				break;	/* NO-NO */			save_flags(flags);			cli();			gus_select_voice(voice);			gus_ramp_range(p1, p2);			restore_flags(flags);			break;		case _GUS_RAMPRATE:			if (voices[voice].mode & WAVE_ENVELOPES)				break;	/* NJET-NJET */			save_flags(flags);			cli();			gus_select_voice(voice);			gus_ramp_rate(p1, p2);			restore_flags(flags);			break;		case _GUS_RAMPMODE:			if (voices[voice].mode & WAVE_ENVELOPES)				break;	/* NO-NO */			save_flags(flags);			cli();			gus_select_voice(voice);			p1 &= ~0x20;	/* Don't allow interrupts */			gus_ramp_mode(p1);			restore_flags(flags);			break;		case _GUS_RAMPON:			if (voices[voice].mode & WAVE_ENVELOPES)				break;	/* EI-EI */			save_flags(flags);			cli();			gus_select_voice(voice);			p1 &= ~0x20;	/* Don't allow interrupts */			gus_rampon(p1);			restore_flags(flags);			break;		case _GUS_RAMPOFF:			if (voices[voice].mode & WAVE_ENVELOPES)				break;	/* NEJ-NEJ */			save_flags(flags);			cli();			gus_select_voice(voice);			gus_rampoff();			restore_flags(flags);			break;		case _GUS_VOLUME_SCALE:			volume_base = p1;			volume_scale = p2;			break;		case _GUS_VOICE_POS:			save_flags(flags);			cli();			gus_select_voice(voice);			gus_set_voice_pos(voice, plong);			restore_flags(flags);			break;		default:	}}static int gus_audio_set_speed(int speed){	if (speed <= 0)		speed = gus_audio_speed;	if (speed < 4000)		speed = 4000;	if (speed > 44100)		speed = 44100;	gus_audio_speed = speed;	if (only_read_access)	{		/* Compute nearest valid recording speed  and return it */		/* speed = (9878400 / (gus_audio_speed + 2)) / 16; */		speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;		speed = (9878400 / (speed * 16)) - 2;	}	return speed;}static int gus_audio_set_channels(int channels){	if (!channels)		return gus_audio_channels;	if (channels > 2)		channels = 2;	if (channels < 1)		channels = 1;	gus_audio_channels = channels;	return channels;}static int gus_audio_set_bits(int bits){	if (!bits)		return gus_audio_bits;	if (bits != 8 && bits != 16)		bits = 8;	if (only_8_bits)		bits = 8;	gus_audio_bits = bits;	return bits;}static int gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg){	int val;	switch (cmd) 	{		case SOUND_PCM_WRITE_RATE:			if (get_user(val, (int *)arg))				return -EFAULT;			val = gus_audio_set_speed(val);			break;		case SOUND_PCM_READ_RATE:			val = gus_audio_speed;			break;		case SNDCTL_DSP_STEREO:			if (get_user(val, (int *)arg))				return -EFAULT;			val = gus_audio_set_channels(val + 1) - 1;			break;		case SOUND_PCM_WRITE_CHANNELS:			if (get_user(val, (int *)arg))				return -EFAULT;			val = gus_audio_set_channels(val);			break;		case SOUND_PCM_READ_CHANNELS:			val = gus_audio_channels;			break;				case SNDCTL_DSP_SETFMT:			if (get_user(val, (int *)arg))				return -EFAULT;			val = gus_audio_set_bits(val);			break;				case SOUND_PCM_READ_BITS:			val = gus_audio_bits;			break;				case SOUND_PCM_WRITE_FILTER:		/* NOT POSSIBLE */		case SOUND_PCM_READ_FILTER:			val = -EINVAL;			break;		default:			return -EINVAL;	}	return put_user(val, (int *)arg);}static void gus_audio_reset(int dev){	if (recording_active)	{		gus_write8(0x49, 0x00);	/* Halt recording */		set_input_volumes();	}}static int saved_iw_mode;	/* A hack hack hack */static int gus_audio_open(int dev, int mode){	if (gus_busy)		return -EBUSY;	if (gus_pnp_flag && mode & OPEN_READ)	{/*		printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/		return -EIO;	}	gus_initialize();	gus_busy = 1;	active_device = 0;	saved_iw_mode = iw_mode;	if (iw_mode)	{		/* There are some problems with audio in enhanced mode so disable it */		gus_write8(0x19, gus_read8(0x19) & ~0x01);	/* Disable enhanced mode */		iw_mode = 0;	}	gus_reset();	reset_sample_memory();	gus_select_max_voices(14);	pcm_active = 0;	dma_active = 0;	pcm_opened = 1;	if (mode & OPEN_READ)	{		recording_active = 1;		set_input_volumes();	}	only_read_access = !(mode & OPEN_WRITE);	only_8_bits = mode & OPEN_READ;	if (only_8_bits)		audio_devs[dev]->format_mask = AFMT_U8;	else		audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;	return 0;}static void gus_audio_close(int dev){	iw_mode = saved_iw_mode;	gus_reset();	gus_busy = 0;	pcm_opened = 0;	active_device = 0;	if (recording_active)	{		gus_write8(0x49, 0x00);	/* Halt recording */		set_input_volumes();	}	recording_active = 0;}static void gus_audio_update_volume(void){	unsigned long flags;	int voice;	if (pcm_active && pcm_opened)

⌨️ 快捷键说明

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