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

📄 dmasound_atari.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		dmasound.hard.speed = 8195;		divider = 11;	}	tt_dmasnd.int_div = divider;	/* Setup Falcon sound DMA for playback */	tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */	tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */	tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */	tt_dmasnd.cbar_dst = 0x0000;	tt_dmasnd.rec_track_select = 0;	tt_dmasnd.dac_src = 2; /* connect matrix to DAC */	tt_dmasnd.adc_src = 0; /* ADC Input = Mic */	tt_dmasnd.mode = (dmasound.hard.stereo ?			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |		((dmasound.hard.size == 8) ?		 DMASND_MODE_8BIT : DMASND_MODE_16BIT) |		DMASND_MODE_6KHZ;	expand_bal = -dmasound.soft.speed;}static int FalconSetFormat(int format){	int size;	/* Falcon sound DMA supports 8bit and 16bit modes */	switch (format) {	case AFMT_QUERY:		return dmasound.soft.format;	case AFMT_MU_LAW:	case AFMT_A_LAW:	case AFMT_U8:	case AFMT_S8:		size = 8;		break;	case AFMT_S16_BE:	case AFMT_U16_BE:	case AFMT_S16_LE:	case AFMT_U16_LE:		size = 16;		break;	default: /* :-) */		size = 8;		format = AFMT_S8;	}	dmasound.soft.format = format;	dmasound.soft.size = size;	if (dmasound.minDev == SND_DEV_DSP) {		dmasound.dsp.format = format;		dmasound.dsp.size = dmasound.soft.size;	}	FalconInit();	return format;}/* This is for the Falcon output *attenuation* in 1.5dB steps, * i.e. output level from 0 to -22.5dB in -1.5dB steps. */#define VOLUME_VOXWARE_TO_ATT(v) \	((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)static int FalconSetVolume(int volume){	dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);	dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);	tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;	return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |	       VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;}static void AtaPlayNextFrame(int index){	char *start, *end;	/* used by AtaPlay() if all doubts whether there really is something	 * to be played are already wiped out.	 */	start = write_sq.buffers[write_sq.front];	end = start+((write_sq.count == index) ? write_sq.rear_size					       : write_sq.block_size);	/* end might not be a legal virtual address. */	DMASNDSetEnd(virt_to_phys(end - 1) + 1);	DMASNDSetBase(virt_to_phys(start));	/* Since only an even number of samples per frame can	   be played, we might lose one byte here. (TO DO) */	write_sq.front = (write_sq.front+1) % write_sq.max_count;	write_sq.active++;	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;}static void AtaPlay(void){	/* ++TeSche: Note that write_sq.active is no longer just a flag but	 * holds the number of frames the DMA is currently programmed for	 * instead, may be 0, 1 (currently being played) or 2 (pre-programmed).	 *	 * Changes done to write_sq.count and write_sq.active are a bit more	 * subtle again so now I must admit I also prefer disabling the irq	 * here rather than considering all possible situations. But the point	 * is that disabling the irq doesn't have any bad influence on this	 * version of the driver as we benefit from having pre-programmed the	 * DMA wherever possible: There's no need to reload the DMA at the	 * exact time of an interrupt but only at some time while the	 * pre-programmed frame is playing!	 */	atari_disable_irq(IRQ_MFP_TIMA);	if (write_sq.active == 2 ||	/* DMA is 'full' */	    write_sq.count <= 0) {	/* nothing to do */		atari_enable_irq(IRQ_MFP_TIMA);		return;	}	if (write_sq.active == 0) {		/* looks like there's nothing 'in' the DMA yet, so try		 * to put two frames into it (at least one is available).		 */		if (write_sq.count == 1 &&		    write_sq.rear_size < write_sq.block_size &&		    !write_sq.syncing) {			/* hmmm, the only existing frame is not			 * yet filled and we're not syncing?			 */			atari_enable_irq(IRQ_MFP_TIMA);			return;		}		AtaPlayNextFrame(1);		if (write_sq.count == 1) {			/* no more frames */			atari_enable_irq(IRQ_MFP_TIMA);			return;		}		if (write_sq.count == 2 &&		    write_sq.rear_size < write_sq.block_size &&		    !write_sq.syncing) {			/* hmmm, there were two frames, but the second			 * one is not yet filled and we're not syncing?			 */			atari_enable_irq(IRQ_MFP_TIMA);			return;		}		AtaPlayNextFrame(2);	} else {		/* there's already a frame being played so we may only stuff		 * one new into the DMA, but even if this may be the last		 * frame existing the previous one is still on write_sq.count.		 */		if (write_sq.count == 2 &&		    write_sq.rear_size < write_sq.block_size &&		    !write_sq.syncing) {			/* hmmm, the only existing frame is not			 * yet filled and we're not syncing?			 */			atari_enable_irq(IRQ_MFP_TIMA);			return;		}		AtaPlayNextFrame(2);	}	atari_enable_irq(IRQ_MFP_TIMA);}static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp){#if 0	/* ++TeSche: if you should want to test this... */	static int cnt;	if (write_sq.active == 2)		if (++cnt == 10) {			/* simulate losing an interrupt */			cnt = 0;			return IRQ_HANDLED;		}#endif	spin_lock(&dmasound.lock);	if (write_sq_ignore_int && is_falcon) {		/* ++TeSche: Falcon only: ignore first irq because it comes		 * immediately after starting a frame. after that, irqs come		 * (almost) like on the TT.		 */		write_sq_ignore_int = 0;		return IRQ_HANDLED;	}	if (!write_sq.active) {		/* playing was interrupted and sq_reset() has already cleared		 * the sq variables, so better don't do anything here.		 */		WAKE_UP(write_sq.sync_queue);		return IRQ_HANDLED;	}	/* Probably ;) one frame is finished. Well, in fact it may be that a	 * pre-programmed one is also finished because there has been a long	 * delay in interrupt delivery and we've completely lost one, but	 * there's no way to detect such a situation. In such a case the last	 * frame will be played more than once and the situation will recover	 * as soon as the irq gets through.	 */	write_sq.count--;	write_sq.active--;	if (!write_sq.active) {		tt_dmasnd.ctrl = DMASND_CTRL_OFF;		write_sq_ignore_int = 1;	}	WAKE_UP(write_sq.action_queue);	/* At least one block of the queue is free now	   so wake up a writing process blocked because	   of a full queue. */	if ((write_sq.active != 1) || (write_sq.count != 1))		/* We must be a bit carefully here: write_sq.count indicates the		 * number of buffers used and not the number of frames to be		 * played. If write_sq.count==1 and write_sq.active==1 that		 * means the only remaining frame was already programmed		 * earlier (and is currently running) so we mustn't call		 * AtaPlay() here, otherwise we'll play one frame too much.		 */		AtaPlay();	if (!write_sq.active) WAKE_UP(write_sq.sync_queue);	/* We are not playing after AtaPlay(), so there	   is nothing to play any more. Wake up a process	   waiting for audio output to drain. */	spin_unlock(&dmasound.lock);	return IRQ_HANDLED;}/*** Mid level stuff *********************************************************//* * /dev/mixer abstraction */#define RECLEVEL_VOXWARE_TO_GAIN(v)	\	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)#define RECLEVEL_GAIN_TO_VOXWARE(v)	(((v) * 20 + 2) / 3)static void __init TTMixerInit(void){	atari_microwire_cmd(MW_LM1992_VOLUME(0));	dmasound.volume_left = 0;	atari_microwire_cmd(MW_LM1992_BALLEFT(0));	dmasound.volume_right = 0;	atari_microwire_cmd(MW_LM1992_BALRIGHT(0));	atari_microwire_cmd(MW_LM1992_TREBLE(0));	atari_microwire_cmd(MW_LM1992_BASS(0));}static void __init FalconMixerInit(void){	dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;	dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;}static int AtaMixerIoctl(u_int cmd, u_long arg){	int data;	unsigned long flags;	switch (cmd) {	    case SOUND_MIXER_READ_SPEAKER:		    if (is_falcon || MACH_IS_TT) {			    int porta;			    spin_lock_irqsave(&dmasound.lock, flags);			    sound_ym.rd_data_reg_sel = 14;			    porta = sound_ym.rd_data_reg_sel;			    spin_unlock_irqrestore(&dmasound.lock, flags);			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);		    }		    break;	    case SOUND_MIXER_WRITE_VOLUME:		    IOCTL_IN(arg, data);		    return IOCTL_OUT(arg, dmasound_set_volume(data));	    case SOUND_MIXER_WRITE_SPEAKER:		    if (is_falcon || MACH_IS_TT) {			    int porta;			    IOCTL_IN(arg, data);			    spin_lock_irqsave(&dmasound.lock, flags);			    sound_ym.rd_data_reg_sel = 14;			    porta = (sound_ym.rd_data_reg_sel & ~0x40) |				    (data < 50 ? 0x40 : 0);			    sound_ym.wd_data = porta;			    spin_unlock_irqrestore(&dmasound.lock, flags);			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);		    }	}	return -EINVAL;}static int TTMixerIoctl(u_int cmd, u_long arg){	int data;	switch (cmd) {	    case SOUND_MIXER_READ_RECMASK:		return IOCTL_OUT(arg, 0);	    case SOUND_MIXER_READ_DEVMASK:		return IOCTL_OUT(arg,				 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |				 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));	    case SOUND_MIXER_READ_STEREODEVS:		return IOCTL_OUT(arg, SOUND_MASK_VOLUME);	    case SOUND_MIXER_READ_VOLUME:		return IOCTL_OUT(arg,				 VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |				 (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));	    case SOUND_MIXER_READ_BASS:		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));	    case SOUND_MIXER_READ_TREBLE:		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));	    case SOUND_MIXER_READ_OGAIN:		return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));	    case SOUND_MIXER_WRITE_BASS:		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, dmasound_set_bass(data));	    case SOUND_MIXER_WRITE_TREBLE:		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, dmasound_set_treble(data));	    case SOUND_MIXER_WRITE_OGAIN:		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, dmasound_set_gain(data));	}	return AtaMixerIoctl(cmd, arg);}static int FalconMixerIoctl(u_int cmd, u_long arg){	int data;	switch (cmd) {	    case SOUND_MIXER_READ_RECMASK:		return IOCTL_OUT(arg, SOUND_MASK_MIC);	    case SOUND_MIXER_READ_DEVMASK:		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);	    case SOUND_MIXER_READ_STEREODEVS:		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);	    case SOUND_MIXER_READ_VOLUME:		return IOCTL_OUT(arg,			VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |			VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);	    case SOUND_MIXER_READ_CAPS:		return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);	    case SOUND_MIXER_WRITE_MIC:		IOCTL_IN(arg, data);		tt_dmasnd.input_gain =			RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |			RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);		/* fall thru, return set value */	    case SOUND_MIXER_READ_MIC:		return IOCTL_OUT(arg,			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);	}	return AtaMixerIoctl(cmd, arg);}static int AtaWriteSqSetup(void){	write_sq_ignore_int = 0;	return 0 ;}static int AtaSqOpen(mode_t mode){	write_sq_ignore_int = 1;	return 0 ;}static int TTStateInfo(char *buffer, size_t space){	int len = 0;	len += sprintf(buffer+len, "\tvol left  %ddB [-40...  0]\n",		       dmasound.volume_left);	len += sprintf(buffer+len, "\tvol right %ddB [-40...  0]\n",		       dmasound.volume_right);	len += sprintf(buffer+len, "\tbass      %ddB [-12...+12]\n",		       dmasound.bass);	len += sprintf(buffer+len, "\ttreble    %ddB [-12...+12]\n",		       dmasound.treble);	if (len >= space) {		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;		len = space ;	}	return len;}static int FalconStateInfo(char *buffer, size_t space){	int len = 0;	len += sprintf(buffer+len, "\tvol left  %ddB [-22.5 ... 0]\n",		       dmasound.volume_left);	len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n",		       dmasound.volume_right);	if (len >= space) {		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;		len = space ;	}	return len;}/*** Machine definitions *****************************************************/static SETTINGS def_hard_falcon = {	.format		= AFMT_S8,	.stereo		= 0,	.size		= 8,	.speed		= 8195} ;static SETTINGS def_hard_tt = {	.format	= AFMT_S8,	.stereo	= 0,	.size	= 8,	.speed	= 12517} ;static SETTINGS def_soft = {	.format	= AFMT_U8,	.stereo	= 0,	.size	= 8,	.speed	= 8000} ;static MACHINE machTT = {	.name		= "Atari",	.name2		= "TT",	.owner		= THIS_MODULE,	.dma_alloc	= AtaAlloc,	.dma_free	= AtaFree,	.irqinit	= AtaIrqInit,#ifdef MODULE	.irqcleanup	= AtaIrqCleanUp,#endif /* MODULE */	.init		= TTInit,	.silence	= TTSilence,	.setFormat	= TTSetFormat,	.setVolume	= TTSetVolume,	.setBass	= AtaSetBass,	.setTreble	= AtaSetTreble,	.setGain	= TTSetGain,	.play		= AtaPlay,	.mixer_init	= TTMixerInit,	.mixer_ioctl	= TTMixerIoctl,	.write_sq_setup	= AtaWriteSqSetup,	.sq_open	= AtaSqOpen,	.state_info	= TTStateInfo,	.min_dsp_speed	= 6258,	.version	= ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),	.hardware_afmts	= AFMT_S8,  /* h'ware-supported formats *only* here */	.capabilities	=  DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */};static MACHINE machFalcon = {	.name		= "Atari",	.name2		= "FALCON",	.dma_alloc	= AtaAlloc,	.dma_free	= AtaFree,	.irqinit	= AtaIrqInit,#ifdef MODULE	.irqcleanup	= AtaIrqCleanUp,#endif /* MODULE */	.init		= FalconInit,	.silence	= FalconSilence,	.setFormat	= FalconSetFormat,	.setVolume	= FalconSetVolume,	.setBass	= AtaSetBass,	.setTreble	= AtaSetTreble,	.play		= AtaPlay,	.mixer_init	= FalconMixerInit,	.mixer_ioctl	= FalconMixerIoctl,	.write_sq_setup	= AtaWriteSqSetup,	.sq_open	= AtaSqOpen,	.state_info	= FalconStateInfo,	.min_dsp_speed	= 8195,	.version	= ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),	.hardware_afmts	= (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */	.capabilities	=  DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */};/*** Config & Setup **********************************************************/static int __init dmasound_atari_init(void){	if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {	    if (ATARIHW_PRESENT(CODEC)) {		dmasound.mach = machFalcon;		dmasound.mach.default_soft = def_soft ;		dmasound.mach.default_hard = def_hard_falcon ;		is_falcon = 1;	    } else if (ATARIHW_PRESENT(MICROWIRE)) {		dmasound.mach = machTT;		dmasound.mach.default_soft = def_soft ;		dmasound.mach.default_hard = def_hard_tt ;		is_falcon = 0;	    } else		return -ENODEV;	    if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)		return dmasound_init();	    else {		printk("DMA sound driver: Timer A interrupt already in use\n");		return -EBUSY;	    }	}	return -ENODEV;}static void __exit dmasound_atari_cleanup(void){	dmasound_deinit();}module_init(dmasound_atari_init);module_exit(dmasound_atari_cleanup);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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