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

📄 dmasound_awacs.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef DEBUG_DMASOUNDprintk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;#endif			/* to clear DEAD status we must first clear RUN			   set it to quiescent to be on the safe side */			(void)in_le32(&awacs_txdma->status);			out_le32(&awacs_txdma->control,				(RUN|PAUSE|FLUSH|WAKE) << 16);			write_sq.died++ ;			if (!emergency_in_use) { /* new problem */				memcpy((void *)emergency_dbdma_cmd, (void *)cp,					sizeof(struct dbdma_cmd));				emergency_in_use = 1;				cp = emergency_dbdma_cmd;			}			/* now bump the values to reflect the amount			   we haven't yet shifted */			req = ld_le16(&cp->req_count);			res = ld_le16(&cp->res_count);			phy = ld_le32(&cp->phy_addr);			phy += (req - res);			st_le16(&cp->req_count, res);			st_le16(&cp->res_count, 0);			st_le16(&cp->xfer_status, 0);			st_le32(&cp->phy_addr, phy);			st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);			/* point at our patched up command block */			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));			/* we must re-start the controller */			(void)in_le32(&awacs_txdma->status);			/* should complete clearing the DEAD status */			out_le32(&awacs_txdma->control,				((RUN|WAKE) << 16) + (RUN|WAKE));			break; /* this block is still going */		}		if ((stat & ACTIVE) == 0)			break;	/* this frame is still going */		if (emergency_in_use)			emergency_in_use = 0 ; /* done that */		--write_sq.count;		--write_sq.active;		if (++i >= write_sq.max_count)			i = 0;	}	/* if we stopped and we were not sync-ing - then we under-ran */	if( write_sq.syncing == 0 ){		stat = in_le32(&awacs_txdma->status) ;		/* we hit the dbdma_stop */		if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ;	}	/* if we used some data up then wake the writer to supply some more*/	if (i != write_sq.front)		WAKE_UP(write_sq.action_queue);	write_sq.front = i;	/* but make sure we funnel what we've already got */\	 if (!awacs_sleeping)		__PMacPlay();	/* make the wake-on-empty conditional on syncing */	if (!write_sq.active && (write_sq.syncing & 1))		WAKE_UP(write_sq.sync_queue); /* any time we're empty */}static voidpmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs){	int stat ;	/* For some reason on my PowerBook G3, I get one interrupt	 * when the interrupt vector is installed (like something is	 * pending).  This happens before the dbdma is initialized by	 * us, so I just check the command pointer and if it is zero,	 * just blow it off.	 */	if (in_le32(&awacs_rxdma->cmdptr) == 0)		return;	/* We also 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 ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) {		/* if we got a "DEAD" status then just log it for now.		   and try to restart dma.		   TODO: figure out how best to fix it up		*/		if (stat & DEAD){#ifdef DEBUG_DMASOUNDprintk("dmasound_pmac: rx-irq: DIED - attempting resurection\n");#endif			/* to clear DEAD status we must first clear RUN			   set it to quiescent to be on the safe side */			(void)in_le32(&awacs_txdma->status);			out_le32(&awacs_txdma->control,				(RUN|PAUSE|FLUSH|WAKE) << 16);			awacs_rx_cmds[read_sq.rear].xfer_status = 0;			awacs_rx_cmds[read_sq.rear].res_count = 0;			read_sq.died++ ;			(void)in_le32(&awacs_txdma->status);			/* re-start the same block */			out_le32(&awacs_rxdma->cmdptr,				virt_to_bus(&awacs_rx_cmds[read_sq.rear]));			/* we must re-start the controller */			(void)in_le32(&awacs_rxdma->status);			/* should complete clearing the DEAD status */			out_le32(&awacs_rxdma->control,				((RUN|WAKE) << 16) + (RUN|WAKE));			return; /* try this block again */		}		/* Clear status and move on to next buffer.		*/		awacs_rx_cmds[read_sq.rear].xfer_status = 0;		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++;			read_sq.xruns++ ; /* we overan */			if (read_sq.front >= read_sq.max_active)				read_sq.front = 0;		}	}	WAKE_UP(read_sq.action_queue);}static voidpmac_awacs_intr(int irq, void *devid, struct pt_regs *regs){	int ctrl = in_le32(&awacs->control);	if (ctrl & MASK_PORTCHG) {		/* do something when headphone is plugged/unplugged? */	}	if (ctrl & MASK_CNTLERR) {		int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;		/* CHECK: we just swallow burgundy errors at the moment..*/		if (err != 0 && awacs_revision != AWACS_BURGUNDY)			printk(KERN_ERR "dmasound_pmac: error %x\n", err);	}	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */	out_le32(&awacs->control, ctrl);}static voidawacs_write(int val){	int count = 300 ;	if (awacs_revision >= AWACS_DACA)		return ;	while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)		udelay(1) ;	/* timeout is > 2 samples at lowest rate */	out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));	(void)in_le32(&awacs->byteswap);}/* this is called when the beep timer expires... it will be called even   if the beep has been overidden by other sound output.*/static void awacs_nosound(unsigned long xx){	unsigned long flags;	int count = 600 ; /* > four samples at lowest rate */	save_flags(flags); cli();	if (beep_playing) {		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);		while ((in_le32(&awacs_txdma->status) & RUN) && count--)			udelay(1);		/* FIXME: check this is OK for DACA, Tumbler */		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);		beep_playing = 0;	}	restore_flags(flags);}static struct timer_list beep_timer = {	function: awacs_nosound};/* we generate the beep with a single dbdma command that loops a buffer   forever - without generating interrupts.   So, to stop it you have to stop dma output as per awacs_nosound.*/static void awacs_mksound(unsigned int hz, unsigned int ticks){	unsigned long flags;	int beep_speed = 0;	int srate;	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 (beep_buf == NULL)		return;	/* quick-hack fix for DACA, Burgundy & Tumbler */	if (awacs_revision >= AWACS_DACA){		srate = 44100 ;	} else {		for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)			if (awacs_freqs_ok[i])				beep_speed = i;		srate = awacs_freqs[beep_speed];	}	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 || write_sq.active || beep_buf == NULL) {		restore_flags(flags);		return;		/* too hard, sorry :-( */	}	beep_playing = 1;	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);	restore_flags(flags);	if (hz == beep_hz_cache && beep_vol == 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_vol;			j = (j + f) & 0xffff;		}		beep_hz_cache = hz;		beep_volume_cache = beep_vol;		beep_nsamples_cache = nsamples;	}	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 */		int count = 300 ;		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);		while ((in_le32(&awacs_txdma->status) & RUN) && count--)			udelay(1); /* timeout > 2 samples at lowest rate*/		/* FIXME: check this is OK on DACA, Tumbler */		out_le32(&awacs->control,			 (in_le32(&awacs->control) & ~0x1f00)			 | (beep_speed << 8));		out_le32(&awacs->byteswap, 0); /* force BE */		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));		(void)in_le32(&awacs_txdma->status);		out_le32(&awacs_txdma->control, RUN | (RUN << 16));	}	restore_flags(flags);}/* used in init and for wake-up */static voidload_awacs(void){	awacs_write(awacs_reg[0] + MASK_ADDR0);	awacs_write(awacs_reg[1] + MASK_ADDR1);	awacs_write(awacs_reg[2] + MASK_ADDR2);	awacs_write(awacs_reg[4] + MASK_ADDR4);	if (awacs_revision == AWACS_SCREAMER) {		awacs_write(awacs_reg[5] + MASK_ADDR5);		wait_ms(100);		awacs_write(awacs_reg[6] + MASK_ADDR6);		wait_ms(2);		awacs_write(awacs_reg[1] + MASK_ADDR1);		awacs_write(awacs_reg[7] + MASK_ADDR7);	}	if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))		out_le32(&awacs->byteswap, BS_VAL);	else		out_le32(&awacs->byteswap, 0);}#ifdef CONFIG_PMAC_PBOOK/* * Save state when going to sleep, restore it afterwards. *//* FIXME: sort out disabling/re-enabling of read stuff as well */static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when){	switch (when) {	case PBOOK_SLEEP_NOW:				LOCK();		awacs_sleeping = 1;		/* Tell the rest of the driver we are now going to sleep */		mb();		if (awacs_revision == AWACS_SCREAMER ||		    awacs_revision == AWACS_AWACS) {			awacs_reg1_save = awacs_reg[1];			awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE;			awacs_write(MASK_ADDR1 | awacs_reg[1]);		}		PMacSilence();		/* stop rx - if going - a bit of a daft user... but */		out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16));		/* deny interrupts */		switch (awacs_revision) {			case AWACS_TUMBLER:				tumbler_enter_sleep(); /* Stub for now */				break ;			case AWACS_DACA:				daca_enter_sleep();				break ;			case AWACS_BURGUNDY:				break ;			case AWACS_SCREAMER:			case AWACS_AWACS:			default:				out_le32(&awacs->control, 0x11) ;				break ;		}		disable_irq(awacs_irq);		disable_irq(awacs_tx_irq);		disable_irq(awacs_rx_irq);		/* Disable sound clock */		pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);		/* According to Darwin, we do that after turning off the sound		 * chip clock. All this will have to be cleaned up once we properly		 * parse the OF sound-objects		 */		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);		}		break;	case PBOOK_WAKE:		/* Enable sound clock */		pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1);		if (machine_is_compatible("PowerBook3,1") ||		    machine_is_compatible("PowerBook3,2")) {			wait_ms(100);			awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1);			awacs_write(MASK_ADDR1 | awacs_reg[1]);			wait_ms(300);		} else			wait_ms(1000); 		/* restore settings */		switch (awacs_revision) {			case AWACS_TUMBLER:				headphone_intr(0,0,0);				tumbler_leave_sleep(); /* Stub for now */				break;			case AWACS_DACA:				wait_ms(10); /* Check this !!! */				daca_leave_sleep();				break ;		/* dont know how yet */			case AWACS_BURGUNDY:				break ;			case AWACS_SCREAMER:			case AWACS_AWACS:			default:		 		load_awacs() ;				break ;		}		/* Recalibrate chip */		if (awacs_revision == AWACS_SCREAMER)			awacs_recalibrate();		/* Make sure dma is stopped */		PMacSilence();		enable_irq(awacs_irq);		enable_irq(awacs_tx_irq); 		enable_irq(awacs_rx_irq); 		/* OK, allow ints back again */ 		out_le32(&awacs->control, MASK_IEPC 		 	| (awacs_rate_index << 8) | 0x11 			 | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); 		if (macio_base && is_pbook_g3) {			/* FIXME: should restore the setup we had...*/			out_8(macio_base + 0x37, 3); 		} else if (is_pbook_3X00) {			in_8(latch_base + 0x190);		}		/* Remove mute */		if (awacs_revision == AWACS_SCREAMER ||		    awacs_revision == AWACS_AWACS) {			awacs_reg[1] = awacs_reg1_save;			awacs_write(MASK_ADDR1 | awacs_reg[1]);		} 		awacs_sleeping = 0;		/* Resume pending sounds. */		/* we don't try to restart input... */		__PMacPlay();		UNLOCK();	}	return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK *//* All the burgundy functions: *//* Waits for busy flag to clear */inline static voidawacs_burgundy_busy_wait(void){	int count = 50; /* > 2 samples at 44k1 */	while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)		udelay(1) ;}inline static voidawacs_burgundy_extend_wait(void){	int count = 50 ; /* > 2 samples at 44k1 */	while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--)		udelay(1) ;	count = 50;	while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--)		udelay(1);}

⌨️ 快捷键说明

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