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

📄 cs4218_tdm.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
static void CS_Init(void){	int i, tolerance;	switch (sound.soft.format) {	case AFMT_S16_LE:	case AFMT_U16_LE:		sound.hard.format = AFMT_S16_LE;		break;	default:		sound.hard.format = AFMT_S16_BE;		break;	}	sound.hard.stereo = 1;	sound.hard.size = 16;	/*	 * If we have a sample rate which is within catchRadius percent	 * of the requested value, we don't have to expand the samples.	 * Otherwise choose the next higher rate.	 */	i = (sizeof(cs4218_freqs) / sizeof(int));	do {		tolerance = catchRadius * cs4218_freqs[--i] / 100;	} while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0);	if (sound.soft.speed >= cs4218_freqs[i] - tolerance)		sound.trans_write = &transCSNormal;	else		sound.trans_write = &transCSExpand;	sound.trans_read = &transCSNormalRead;	sound.hard.speed = cs4218_freqs[i];	cs4218_rate_index = i;	/* The CS4218 has seven selectable clock dividers for the sample	 * clock.  The HIOX then provides one of two external rates.	 * An even numbered frequency table index uses the high external	 * clock rate.	 */	*(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL);	if ((i & 1) == 0)		*(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI;	i >>= 1;	*(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL);	expand_bal = -sound.soft.speed;}static int CS_SetFormat(int format){	int size;	switch (format) {	case AFMT_QUERY:		return sound.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: /* :-) */		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",		       format);		size = 8;		format = AFMT_U8;	}	sound.soft.format = format;	sound.soft.size = size;	if (sound.minDev == SND_DEV_DSP) {		sound.dsp.format = format;		sound.dsp.size = size;	}	CS_Init();	return format;}/* Volume is the amount of attenuation we tell the codec to impose * on the outputs.  There are 32 levels, with 0 the "loudest". */#define CS_VOLUME_TO_MASK(x)	(31 - ((((x) - 1) * 31) / 99))#define CS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 31))static int cs_get_volume(uint reg){	int volume;	volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg));	volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8;	return volume;}static int cs_volume_setter(int volume, int mute){	uint tempctl;	if (mute && volume == 0) {		tempctl = cs4218_control | CS_MUTE;	} else {		tempctl = cs4218_control & ~CS_MUTE;		tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN);		tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff));		tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff));		volume = cs_get_volume(tempctl);	}	if (tempctl != cs4218_control) {		cs4218_ctl_write(tempctl);	}	return volume;}/* Gain has 16 steps from 0 to 15.  These are in 1.5dB increments from * 0 (no gain) to 22.5 dB. */#define CS_RECLEVEL_TO_GAIN(v) \	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3)static int cs_get_gain(uint reg){	int gain;	gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg));	gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8;	return gain;}static int cs_set_gain(int gain){	uint tempctl;	tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN);	tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff));	tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff));	gain = cs_get_gain(tempctl);	if (tempctl != cs4218_control) {		cs4218_ctl_write(tempctl);	}	return gain;}static int CS_SetVolume(int volume){	return cs_volume_setter(volume, CS_MUTE);}static void CS_Play(void){	int i, count;	unsigned long flags;	volatile cbd_t	*bdp;	volatile cpm8xx_t *cp;	save_flags(flags); cli();#if 0	if (awacs_beep_state) {		/* sound takes precedence over beeps */		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);		out_le32(&awacs->control,			 (in_le32(&awacs->control) & ~0x1f00)			 | (awacs_rate_index << 8));		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));		beep_playing = 0;		awacs_beep_state = 0;	}#endif	i = sq.front + sq.active;	if (i >= sq.max_count)		i -= sq.max_count;	while (sq.active < 2 && sq.active < sq.count) {		count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;		if (count < sq.block_size && !sq.syncing)			/* last block not yet filled, and we're not syncing. */			break;		bdp = &tx_base[i];		bdp->cbd_datlen = count;		flush_dcache_range((ulong)sound_buffers[i],					(ulong)(sound_buffers[i] + count));		if (++i >= sq.max_count)			i = 0;		if (sq.active == 0) {			/* The SMC does not load its fifo until the first			 * TDM frame pulse, so the transmit data gets shifted			 * by one word.  To compensate for this, we incorrectly			 * transmit the first buffer and shorten it by one			 * word.  Subsequent buffers are then aligned properly.			 */			bdp->cbd_datlen -= 2;			/* Start up the SMC Transmitter.			*/			cp = cpmp;			cp->cp_smc[1].smc_smcmr |= SMCMR_TEN;			cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,					CPM_CR_RESTART_TX) | CPM_CR_FLG;			while (cp->cp_cpcr & CPM_CR_FLG);		}		/* Buffer is ready now.		*/		bdp->cbd_sc |= BD_SC_READY;		++sq.active;	}	restore_flags(flags);}static void CS_Record(void){	unsigned long flags;	volatile smc_t		*sp;	if (read_sq.active)		return;	save_flags(flags); cli();	/* This is all we have to do......Just start it up.	*/	sp = &cpmp->cp_smc[1];	sp->smc_smcmr |= SMCMR_REN;	read_sq.active = 1;        restore_flags(flags);}static voidcs4218_tdm_tx_intr(void *devid){	int i = sq.front;	volatile cbd_t *bdp;	while (sq.active > 0) {		bdp = &tx_base[i];		if (bdp->cbd_sc & BD_SC_READY)			break;	/* this frame is still going */		--sq.count;		--sq.active;		if (++i >= sq.max_count)			i = 0;	}	if (i != sq.front)		WAKE_UP(sq.action_queue);	sq.front = i;	CS_Play();	if (!sq.active)		WAKE_UP(sq.sync_queue);}static voidcs4218_tdm_rx_intr(void *devid){	/* We want to blow 'em off when shutting down.	*/	if (read_sq.active == 0)		return;	/* Check multiple buffers in case we were held off from	 * interrupt processing for a long time.  Geeze, I really hope	 * this doesn't happen.	 */	while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) {		/* Invalidate the data cache range for this buffer.		*/		invalidate_dcache_range(		    (uint)(sound_read_buffers[read_sq.rear]),		    (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size));		/* Make buffer available again and move on.		*/		rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY;		read_sq.rear++;		/* Wrap the buffer ring.		*/		if (read_sq.rear >= read_sq.max_active)			read_sq.rear = 0;		/* If we have caught up to the front buffer, bump it.		 * This will cause weird (but not fatal) results if the		 * read loop is currently using this buffer.  The user is		 * behind in this case anyway, so weird things are going		 * to happen.		 */		if (read_sq.rear == read_sq.front) {			read_sq.front++;			if (read_sq.front >= read_sq.max_active)				read_sq.front = 0;		}	}	WAKE_UP(read_sq.action_queue);}static void cs_nosound(unsigned long xx){	unsigned long flags;	save_flags(flags); cli();	if (beep_playing) {#if 0		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);#endif		beep_playing = 0;	}	restore_flags(flags);}static struct timer_list beep_timer = {	function: cs_nosound};static void cs_mksound(unsigned int hz, unsigned int ticks){	unsigned long flags;	int beep_speed = BEEP_SPEED;	int srate = cs4218_freqs[beep_speed];	int period, ncycles, nsamples;	int i, j, f;	short *p;	static int beep_hz_cache;	static int beep_nsamples_cache;	static int beep_volume_cache;	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {#if 1		/* this is a hack for broken X server code */		hz = 750;		ticks = 12;#else		/* cancel beep currently playing */		awacs_nosound(0);		return;#endif	}	save_flags(flags); cli();	del_timer(&beep_timer);	if (ticks) {		beep_timer.expires = jiffies + ticks;		add_timer(&beep_timer);	}	if (beep_playing || sq.active || beep_buf == NULL) {		restore_flags(flags);		return;		/* too hard, sorry :-( */	}	beep_playing = 1;#if 0	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);#endif	restore_flags(flags);	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {		nsamples = beep_nsamples_cache;	} else {		period = srate * 256 / hz;	/* fixed point */		ncycles = BEEP_BUFLEN * 256 / period;		nsamples = (period * ncycles) >> 8;		f = ncycles * 65536 / nsamples;		j = 0;		p = beep_buf;		for (i = 0; i < nsamples; ++i, p += 2) {			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;			j = (j + f) & 0xffff;		}		beep_hz_cache = hz;		beep_volume_cache = beep_volume;		beep_nsamples_cache = nsamples;	}#if 0	st_le16(&beep_dbdma_cmd->req_count, nsamples*4);	st_le16(&beep_dbdma_cmd->xfer_status, 0);	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));	awacs_beep_state = 1;	save_flags(flags); cli();	if (beep_playing) {	/* i.e. haven't been terminated already */		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);		out_le32(&awacs->control,			 (in_le32(&awacs->control) & ~0x1f00)			 | (beep_speed << 8));		out_le32(&awacs->byteswap, 0);		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));		out_le32(&awacs_txdma->control, RUN | (RUN << 16));	}#endif	restore_flags(flags);}static void CS_open(void){	MOD_INC_USE_COUNT;}static void CS_release(void){	MOD_DEC_USE_COUNT;}static MACHINE mach_cs4218 = {	name:		"HIOX CS4218",	name2:		"Built-in Sound",	open:		CS_open,	release:	CS_release,	dma_alloc:	CS_Alloc,	dma_free:	CS_Free,	irqinit:	CS_IrqInit,#ifdef MODULE	irqcleanup:	CS_IrqCleanup,#endif /* MODULE */	init:		CS_Init,	silence:	CS_Silence,	setFormat:	CS_SetFormat,	setVolume:	CS_SetVolume,	play:		CS_Play};/*** Mid level stuff *********************************************************/static void sound_silence(void){	/* update hardware settings one more */	(*sound.mach.init)();	(*sound.mach.silence)();}static void sound_init(void){	(*sound.mach.init)();}static int sound_set_format(int format){	return(*sound.mach.setFormat)(format);}static int sound_set_speed(int speed){	if (speed < 0)		return(sound.soft.speed);	sound.soft.speed = speed;	(*sound.mach.init)();	if (sound.minDev == SND_DEV_DSP)		sound.dsp.speed = sound.soft.speed;	return(sound.soft.speed);}static int sound_set_stereo(int stereo){	if (stereo < 0)		return(sound.soft.stereo);	stereo = !!stereo;    /* should be 0 or 1 now */	sound.soft.stereo = stereo;	if (sound.minDev == SND_DEV_DSP)		sound.dsp.stereo = stereo;	(*sound.mach.init)();	return(stereo);}static int sound_set_volume(int volume){	return(*sound.mach.setVolume)(volume);}static ssize_t sound_copy_translate(const u_char *userPtr,				    size_t userCount,				    u_char frame[], ssize_t *frameUsed,				    ssize_t frameLeft){	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;	switch (sound.soft.format) {	case AFMT_MU_LAW:		ct_func = sound.trans_write->ct_ulaw;		break;	case AFMT_A_LAW:		ct_func = sound.trans_write->ct_alaw;		break;	case AFMT_S8:		ct_func = sound.trans_write->ct_s8;		break;	case AFMT_U8:		ct_func = sound.trans_write->ct_u8;

⌨️ 快捷键说明

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