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

📄 dmasound_awacs.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
static intawacs_tumbler_cleanup(void){	if (gpio_headphone_irq)		free_irq(gpio_headphone_irq, 0);	return 0;}/*** AE - TUMBLER END *********************************************************//*** Low level stuff *********************************************************//* * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. */static void PMacOpen(void){	MOD_INC_USE_COUNT;}static void PMacRelease(void){	MOD_DEC_USE_COUNT;}static void *PMacAlloc(unsigned int size, int flags){	return kmalloc(size, flags);}static void PMacFree(void *ptr, unsigned int size){	kfree(ptr);}static int __init PMacIrqInit(void){	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0)	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0)	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", 0))		return 0;	return 1;}#ifdef MODULEstatic void PMacIrqCleanup(void){	/* turn off input & output dma */	DBDMA_DO_STOP(awacs_txdma);	DBDMA_DO_STOP(awacs_rxdma);	/* disable interrupts from awacs interface */	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);	/* Switch off the sound clock */	pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);	/* Make sure proper bits are set on pismo & tipb */	if (machine_is_compatible("PowerBook3,1") ||	    machine_is_compatible("PowerBook3,2")) {		awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;		awacs_write(MASK_ADDR1 | awacs_reg[1]);		wait_ms(200);	}	free_irq(awacs_irq, 0);	free_irq(awacs_tx_irq, 0);	free_irq(awacs_rx_irq, 0);	/* all OF versions I've seen use this value */	iounmap((void *)awacs);	iounmap((void *)awacs_txdma);	iounmap((void *)awacs_rxdma);	release_OF_resource(awacs_node, 0);	release_OF_resource(awacs_node, 1);	release_OF_resource(awacs_node, 2);	if (awacs_tx_cmd_space)		kfree(awacs_tx_cmd_space);	if (awacs_rx_cmd_space)		kfree(awacs_rx_cmd_space);	if (beep_dbdma_cmd_space)		kfree(beep_dbdma_cmd_space);	if (beep_buf) {		kfree(beep_buf);		kd_mksound = orig_mksound;	}#ifdef CONFIG_PMAC_PBOOK	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);#endif}#endif /* MODULE */static void PMacSilence(void){	/* turn off output dma */	DBDMA_DO_STOP(awacs_txdma);}static int tumbler_freqs[2] = { 48000, 44100 } ;static int tumbler_freqs_ok[2] = { 1, 1 } ;/* don't know what to do really - just have to leave it where * OF left things*/static int tumbler_set_frame_rate(void){	dmasound.hard.speed = 44100 ;	awacs_rate_index = 0 ;	return 44100 ;}/* don't know what to do really - just have to leave it where * OF left things*/static int daca_set_frame_rate(void){	dmasound.hard.speed = 44100 ;	awacs_rate_index = 0 ;	return 44100 ;}static int awacs_freqs[8] = {	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350};static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };static int awacs_set_frame_rate(int desired, int catch_r){	int tolerance, i = 8 ;	/*	 * 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.	 * N.B.: burgundy awacs only works at 44100 Hz.	 */	do {		tolerance = catch_r * awacs_freqs[--i] / 100;		if (awacs_freqs_ok[i]		    && dmasound.soft.speed <= awacs_freqs[i] + tolerance)			break;	} while (i > 0);	dmasound.hard.speed = awacs_freqs[i];	awacs_rate_index = i;	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 );	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);	awacs_write(awacs_reg[1] | MASK_ADDR1);	return dmasound.hard.speed;}static int burgundy_frame_rates = 1 ;static int burgundy_set_frame_rate(void){#ifdef DEBUG_DMASOUNDif (burgundy_frame_rates > 1)	printk("dmasound_pmac: warning Burgundy had more than one frame rate\n");#endif	awacs_rate_index = 0 ;	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ;	/* XXX disable error interrupt on burgundy for now */	out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE);	return 44100 ;}static int set_frame_rate(int desired, int catch_r){	switch (awacs_revision) {		case AWACS_BURGUNDY:			dmasound.hard.speed =			  burgundy_set_frame_rate();			break ;		case AWACS_TUMBLER:			dmasound.hard.speed =			  tumbler_set_frame_rate();			break ;		case AWACS_DACA:			dmasound.hard.speed =			  daca_set_frame_rate();			break ;		default:			dmasound.hard.speed =			  awacs_set_frame_rate(desired, catch_r);			break ;	}	return dmasound.hard.speed ;}static voidawacs_recalibrate(void){	/* Sorry for the horrible delays... I hope to get that improved	 * by making the whole PM process asynchronous in a future version	 */	wait_ms(750);	awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE;	awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1);	wait_ms(1000);	awacs_write(awacs_reg[1] | MASK_ADDR1);}static void PMacInit(void){	int tolerance;	switch (dmasound.soft.format) {	    case AFMT_S16_LE:	    case AFMT_U16_LE:		if (hw_can_byteswap)			dmasound.hard.format = AFMT_S16_LE;		else			dmasound.hard.format = AFMT_S16_BE;		break;	default:		dmasound.hard.format = AFMT_S16_BE;		break;	}	dmasound.hard.stereo = 1;	dmasound.hard.size = 16;	/* set dmasound.hard.speed - on the basis of what we want (soft)	 * and the tolerance we'll allow.	*/	set_frame_rate(dmasound.soft.speed, catchRadius) ;	tolerance = (catchRadius * dmasound.hard.speed) / 100;	if (dmasound.soft.speed >= dmasound.hard.speed - tolerance)		dmasound.trans_write = &transAwacsNormal;	else		dmasound.trans_write = &transAwacsExpand;	dmasound.trans_read = &transAwacsNormalRead;	if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))		out_le32(&awacs->byteswap, BS_VAL);	else		out_le32(&awacs->byteswap, 0);	expand_bal = -dmasound.soft.speed;}static int PMacSetFormat(int format){	int size;	int req_format = format;			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_LE:		if(!hw_can_byteswap)			format = AFMT_S16_BE;	case AFMT_S16_BE:		size = 16;		break;	case AFMT_U16_LE:		if(!hw_can_byteswap)			format = AFMT_U16_BE;	case AFMT_U16_BE:		size = 16;		break;	default: /* :-) */		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",		       format);		size = 8;		format = AFMT_U8;	}		if (req_format == format) {		dmasound.soft.format = format;		dmasound.soft.size = size;		if (dmasound.minDev == SND_DEV_DSP) {			dmasound.dsp.format = format;			dmasound.dsp.size = size;		}	}	return format;}#define AWACS_VOLUME_TO_MASK(x)	(15 - ((((x) - 1) * 15) / 99))#define AWACS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 15))static int awacs_get_volume(int reg, int lshift){	int volume;	volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);	volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;	return volume;}static int awacs_volume_setter(int volume, int n, int mute, int lshift){	int r1, rn;	if (mute && volume == 0) {		r1 = awacs_reg[1] | mute;	} else {		r1 = awacs_reg[1] & ~mute;		rn = awacs_reg[n] & ~(0xf | (0xf << lshift));		rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);		rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;		awacs_reg[n] = rn;		awacs_write((n << 12) | rn);		volume = awacs_get_volume(rn, lshift);	}	if (r1 != awacs_reg[1]) {		awacs_reg[1] = r1;		awacs_write(r1 | MASK_ADDR1);	}	return volume;}static int PMacSetVolume(int volume){	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);}static void __PMacPlay(void){	volatile struct dbdma_cmd *cp;	int next_frg, count;	unsigned long flags;	/* CHECK: how much of this *really* needs IRQs masked? */	save_flags(flags); cli();	count = 300 ; /* > two cycles at the lowest sample rate */	/* what we want to send next */	next_frg = (write_sq.front + write_sq.active) % write_sq.max_count;	if (awacs_beep_state) {		/* sound takes precedence over beeps */		/* stop the dma channel */		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);		while ( (in_le32(&awacs_txdma->status) & RUN) && count--)			udelay(1);		/* FIXME: check that this is OK for other chip sets */		out_le32(&awacs->control,			 (in_le32(&awacs->control) & ~0x1f00)			 | (awacs_rate_index << 8));		if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))			out_le32(&awacs->byteswap, BS_VAL);		else			out_le32(&awacs->byteswap, 0);		out_le32(&awacs_txdma->cmdptr,			 virt_to_bus(&(awacs_tx_cmds[next_frg])));		beep_playing = 0;		awacs_beep_state = 0;	}	/* this won't allow more than two frags to be in the output queue at	   once. (or one, if the max frags is 2 - because count can't exceed	   2 in that case)	*/	while (write_sq.active < 2 && write_sq.active < write_sq.count) {		count = (write_sq.count == write_sq.active + 1) ?				write_sq.rear_size:write_sq.block_size ;		if (count < write_sq.block_size) {			if (!write_sq.syncing) /* last block not yet filled,*/				break; 	/* and we're not syncing or POST-ed */			else {				/* pretend the block is full to force a new				   block to be started on the next write */				write_sq.rear_size = write_sq.block_size ;				write_sq.syncing &= ~2 ; /* clear POST */			}		}		cp = &awacs_tx_cmds[next_frg];		st_le16(&cp->req_count, count);		st_le16(&cp->xfer_status, 0);		st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);		/* put a STOP at the end of the queue - but only if we have		   space for it.  This means that, if we under-run and we only		   have two fragments, we might re-play sound from an existing		   queued frag.  I guess the solution to that is not to set two		   frags if you are likely to under-run...		*/		if (write_sq.count < write_sq.max_count) {			if (++next_frg >= write_sq.max_count)				next_frg = 0 ; /* wrap */			/* if we get here then we've underrun so we will stop*/			st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP);		}		/* set the dbdma controller going, if it is not already */		if (write_sq.active == 0)			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));		(void)in_le32(&awacs_txdma->status);		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));		++write_sq.active;	}	restore_flags(flags);}static void PMacPlay(void){	LOCK();	if (!awacs_sleeping)		__PMacPlay();	UNLOCK();}static void PMacRecord(void){	unsigned long flags;	if (read_sq.active)		return;	save_flags(flags); cli();	/* This is all we have to do......Just start it up.	*/	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));	read_sq.active = 1;	restore_flags(flags);}/* if the TX status comes up "DEAD" - reported on some Power Computing machines   we need to re-start the dbdma - but from a different physical start address   and with a different transfer length.  It would get very messy to do this   with the normal dbdma_cmd blocks - we would have to re-write the buffer start   addresses each time.  So, we will keep a single dbdma_cmd block which can be   fiddled with.   When DEAD status is first reported the content of the faulted dbdma block is   copied into the emergency buffer and we note that the buffer is in use.   we then bump the start physical address by the amount that was successfully   output before it died.   On any subsequent DEAD result we just do the bump-ups (we know that we are   already using the emergency dbdma_cmd).   CHECK: this just tries to "do it".  It is possible that we should abandon   xfers when the number of residual bytes gets below a certain value - I can   see that this might cause a loop-forever if too small a transfer causes   DEAD status.  However this is a TODO for now - we'll see what gets reported.   When we get a successful transfer result with the emergency buffer we just   pretend that it completed using the original dmdma_cmd and carry on.  The   'next_cmd' field will already point back to the original loop of blocks.*/static voidpmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs){	int i = write_sq.front;	int stat;	volatile struct dbdma_cmd *cp;	/* != 0 when we are dealing with a DEAD xfer */	static int emergency_in_use = 0 ;	while (write_sq.active > 0) { /* we expect to have done something*/		if (emergency_in_use) /* we are dealing with DEAD xfer */			cp = emergency_dbdma_cmd ;		else			cp = &awacs_tx_cmds[i];		stat = ld_le16(&cp->xfer_status);		if (stat & DEAD) {			unsigned short req, res ;			unsigned int phy ;

⌨️ 快捷键说明

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