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

📄 ali5451.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	wCount = 200;	while(wCount--) {		wReg = snd_ali_codec_read(codec->ac97, AC97_POWERDOWN);		if((wReg & 0x000f) == 0x000f)			return 0;		udelay(5000);	}	return -1;}#endif/* *  ALI 5451 Controller */static void snd_ali_enable_special_channel(ali_t *codec, unsigned int channel){	unsigned long dwVal = 0;	dwVal  = inl(ALI_REG(codec,ALI_GLOBAL_CONTROL));	dwVal |= 1 << (channel & 0x0000001f);	outl(dwVal, ALI_REG(codec,ALI_GLOBAL_CONTROL));}static void snd_ali_disable_special_channel(ali_t *codec, unsigned int channel){	unsigned long dwVal = 0;	dwVal  = inl(ALI_REG(codec,ALI_GLOBAL_CONTROL));	dwVal &= ~(1 << (channel & 0x0000001f));	outl(dwVal, ALI_REG(codec,ALI_GLOBAL_CONTROL));}static void snd_ali_enable_address_interrupt(ali_t * codec){	unsigned int gc;	gc  = inl(ALI_REG(codec, ALI_GC_CIR));	gc |= ENDLP_IE;	gc |= MIDLP_IE;	outl( gc, ALI_REG(codec, ALI_GC_CIR));}static void snd_ali_disable_address_interrupt(ali_t * codec){	unsigned int gc;	gc  = inl(ALI_REG(codec, ALI_GC_CIR));	gc &= ~ENDLP_IE;	gc &= ~MIDLP_IE;	outl(gc, ALI_REG(codec, ALI_GC_CIR));}#if 0 // not usedstatic void snd_ali_enable_voice_irq(ali_t *codec, unsigned int channel){	unsigned int mask;	snd_ali_channel_control_t *pchregs = &(codec->chregs);	snd_ali_printk("enable_voice_irq channel=%d\n",channel);		mask = 1 << (channel & 0x1f);	pchregs->data.ainten  = inl(ALI_REG(codec,pchregs->regs.ainten));	pchregs->data.ainten |= mask;	outl(pchregs->data.ainten,ALI_REG(codec,pchregs->regs.ainten));}#endifstatic void snd_ali_disable_voice_irq(ali_t *codec, unsigned int channel){	unsigned int mask;	snd_ali_channel_control_t *pchregs = &(codec->chregs);	snd_ali_printk("disable_voice_irq channel=%d\n",channel);	mask = 1 << (channel & 0x1f);	pchregs->data.ainten  = inl(ALI_REG(codec,pchregs->regs.ainten));	pchregs->data.ainten &= ~mask;	outl(pchregs->data.ainten,ALI_REG(codec,pchregs->regs.ainten));}static int snd_ali_alloc_pcm_channel(ali_t *codec, int channel){	unsigned int idx =  channel & 0x1f;	if (codec->synth.chcnt >= ALI_CHANNELS){		snd_printk("ali_alloc_pcm_channel: no free channels.\n");		return -1;	}	if (!(codec->synth.chmap & (1 << idx))) {		codec->synth.chmap |= 1 << idx;		codec->synth.chcnt++;		snd_ali_printk("alloc_pcm_channel no. %d.\n",idx);		return idx;	}	return -1;}static int snd_ali_find_free_channel(ali_t * codec, int rec){	int idx;	int result = -1;	snd_ali_printk("find_free_channel: for %s\n",rec ? "rec" : "pcm");	// recording	if (rec) {		if (codec->spdif_support &&		    (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_IN_SUPPORT))			idx = ALI_SPDIF_IN_CHANNEL;		else			idx = ALI_PCM_IN_CHANNEL;		if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) {			return result;		} else {			snd_printk("ali_find_free_channel: record channel is busy now.\n");			return -1;		}	}	//playback...	if (codec->spdif_support &&	    (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE)) {		idx = ALI_SPDIF_OUT_CHANNEL;		if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) {			return result;		} else {			snd_printk("ali_find_free_channel: S/PDIF out channel is in busy now.\n");		}	}	for (idx = 0; idx < ALI_CHANNELS; idx++) {		if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0)			return result;	}	snd_printk("ali_find_free_channel: no free channels.\n");	return -1;}static void snd_ali_free_channel_pcm(ali_t *codec, int channel){	unsigned int idx = channel & 0x0000001f;	snd_ali_printk("free_channel_pcm channel=%d\n",channel);	if (channel < 0 || channel >= ALI_CHANNELS)		return;	if (!(codec->synth.chmap & (1 << idx))) {		snd_printk("ali_free_channel_pcm: channel %d is not in use.\n",channel);		return;	} else {		codec->synth.chmap &= ~(1 << idx);		codec->synth.chcnt--;	}}#if 0 // not usedstatic void snd_ali_start_voice(ali_t * codec, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);		snd_ali_printk("start_voice: channel=%d\n",channel);	outl(mask, ALI_REG(codec,codec->chregs.regs.start));}#endifstatic void snd_ali_stop_voice(ali_t * codec, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);	snd_ali_printk("stop_voice: channel=%d\n",channel);	outl(mask, ALI_REG(codec, codec->chregs.regs.stop));}/* *    S/PDIF Part */static void snd_ali_delay(ali_t *codec,int interval){	unsigned long  begintimer,currenttimer;	begintimer   = inl(ALI_REG(codec, ALI_STIMER));	currenttimer = inl(ALI_REG(codec, ALI_STIMER));	while (currenttimer < begintimer + interval) {		if(snd_ali_stimer_ready(codec, 1) < 0)			break;		currenttimer = inl(ALI_REG(codec,  ALI_STIMER));	}}static void snd_ali_detect_spdif_rate(ali_t *codec){	u16 wval  = 0;	u16 count = 0;	u8  bval = 0, R1 = 0, R2 = 0;	bval  = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));	bval |= 0x1F;	outb(bval,ALI_REG(codec,ALI_SPDIF_CTRL + 1));	while (((R1 < 0x0B )||(R1 > 0x0E)) && (R1 != 0x12) && count <= 50000) {		count ++;		snd_ali_delay(codec, 6);		bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));		R1 = bval & 0x1F;	}	if (count > 50000) {		snd_printk("ali_detect_spdif_rate: timeout!\n");		return;	}	count = 0;	while (count++ <= 50000) {		snd_ali_delay(codec, 6);		bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));		R2 = bval & 0x1F;		if (R2 != R1) R1 = R2; else break;	}	if (count > 50000) {		snd_printk("ali_detect_spdif_rate: timeout!\n");		return;	}	if (R2 >= 0x0b && R2 <= 0x0e) {		wval  = inw(ALI_REG(codec,ALI_SPDIF_CTRL + 2));		wval &= 0xE0F0;		wval |= (u16)0x09 << 8 | (u16)0x05;		outw(wval,ALI_REG(codec,ALI_SPDIF_CTRL + 2));		bval  = inb(ALI_REG(codec,ALI_SPDIF_CS +3)) & 0xF0;		outb(bval|0x02,ALI_REG(codec,ALI_SPDIF_CS + 3));	} else if (R2 == 0x12) {		wval  = inw(ALI_REG(codec,ALI_SPDIF_CTRL + 2));		wval &= 0xE0F0;		wval |= (u16)0x0E << 8 | (u16)0x08;		outw(wval,ALI_REG(codec,ALI_SPDIF_CTRL + 2));		bval  = inb(ALI_REG(codec,ALI_SPDIF_CS +3)) & 0xF0;		outb(bval|0x03,ALI_REG(codec,ALI_SPDIF_CS + 3));	}}static unsigned int snd_ali_get_spdif_in_rate(ali_t *codec){	u32	dwRate = 0;	u8	bval = 0;	bval  = inb(ALI_REG(codec,ALI_SPDIF_CTRL));	bval &= 0x7F;	bval |= 0x40;	outb(bval, ALI_REG(codec,ALI_SPDIF_CTRL));	snd_ali_detect_spdif_rate(codec);	bval  = inb(ALI_REG(codec,ALI_SPDIF_CS + 3));	bval &= 0x0F;	if (bval == 0) dwRate = 44100;	if (bval == 1) dwRate = 48000;	if (bval == 2) dwRate = 32000;	return dwRate;}static void snd_ali_enable_spdif_in(ali_t *codec){		unsigned int dwVal;	dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));	dwVal |= ALI_SPDIF_IN_SUPPORT;	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));	dwVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL));	dwVal |= 0x02;	outb(dwVal, ALI_REG(codec, ALI_SPDIF_CTRL));	snd_ali_enable_special_channel(codec, ALI_SPDIF_IN_CHANNEL);}static void snd_ali_disable_spdif_in(ali_t *codec){	unsigned int dwVal;		dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));	dwVal &= ~ALI_SPDIF_IN_SUPPORT;	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));		snd_ali_disable_special_channel(codec, ALI_SPDIF_IN_CHANNEL);	}static void snd_ali_set_spdif_out_rate(ali_t *codec, unsigned int rate){	unsigned char  bVal;	unsigned int  dwRate = 0;		if (rate == 32000) dwRate = 0x300;	if (rate == 44100) dwRate = 0;	if (rate == 48000) dwRate = 0x200;		bVal  = inb(ALI_REG(codec, ALI_SPDIF_CTRL));	bVal &= (unsigned char)(~(1<<6));		bVal |= 0x80;		//select right	outb(bVal, ALI_REG(codec, ALI_SPDIF_CTRL));	outb(dwRate | 0x20, ALI_REG(codec, ALI_SPDIF_CS + 2));		bVal &= (~0x80);	//select left	outb(bVal, ALI_REG(codec, ALI_SPDIF_CTRL));	outw(rate | 0x10, ALI_REG(codec, ALI_SPDIF_CS + 2));}static void snd_ali_enable_spdif_out(ali_t *codec){	unsigned short wVal;	unsigned char bVal;        struct pci_dev *pci_dev = NULL;        pci_dev = codec->pci_m1533;        if (pci_dev == NULL)                return;        pci_read_config_byte(pci_dev, 0x61, &bVal);        bVal |= 0x40;        pci_write_config_byte(pci_dev, 0x61, bVal);        pci_read_config_byte(pci_dev, 0x7d, &bVal);        bVal |= 0x01;        pci_write_config_byte(pci_dev, 0x7d, bVal);        pci_read_config_byte(pci_dev, 0x7e, &bVal);        bVal &= (~0x20);        bVal |= 0x10;        pci_write_config_byte(pci_dev, 0x7e, bVal);	bVal = inb(ALI_REG(codec, ALI_SCTRL));	outb(bVal | ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL));	bVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL));	outb(bVal & ALI_SPDIF_OUT_CH_STATUS, ALI_REG(codec, ALI_SPDIF_CTRL));   	{   		wVal = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));   		wVal |= ALI_SPDIF_OUT_SEL_PCM;   		outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));		snd_ali_disable_special_channel(codec,ALI_SPDIF_OUT_CHANNEL);   	}}static void snd_ali_enable_spdif_chnout(ali_t *codec){	unsigned short wVal = 0;	wVal  = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));   	wVal &= ~ALI_SPDIF_OUT_SEL_PCM;   	outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));/*	wVal = inw(ALI_REG(codec, ALI_SPDIF_CS));	if (flag & ALI_SPDIF_OUT_NON_PCM)   		wVal |= 0x0002;	else			wVal &= (~0x0002);   	outw(wVal, ALI_REG(codec, ALI_SPDIF_CS));*/	snd_ali_enable_special_channel(codec,ALI_SPDIF_OUT_CHANNEL);}static void snd_ali_disable_spdif_chnout(ali_t *codec){	unsigned short wVal = 0;  	wVal  = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL));   	wVal |= ALI_SPDIF_OUT_SEL_PCM;   	outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));	snd_ali_enable_special_channel(codec, ALI_SPDIF_OUT_CHANNEL);}static void snd_ali_disable_spdif_out(ali_t *codec){	unsigned char  bVal;	bVal = inb(ALI_REG(codec, ALI_SCTRL));	outb(bVal & ~ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL));	snd_ali_disable_spdif_chnout(codec);}static void snd_ali_update_ptr(ali_t *codec,int channel){	snd_ali_voice_t *pvoice = NULL;	snd_pcm_runtime_t *runtime;	snd_ali_channel_control_t *pchregs = NULL;	unsigned int old, mask;#ifdef ALI_DEBUG	unsigned int temp, cspf;#endif	pchregs = &(codec->chregs);	// check if interrupt occurred for channel	old  = pchregs->data.aint;	mask = ((unsigned int) 1L) << (channel & 0x1f);	if (!(old & mask))		return;	pvoice = &codec->synth.voices[channel];	runtime = pvoice->substream->runtime;	udelay(100);	spin_lock(&codec->reg_lock);	if (pvoice->pcm && pvoice->substream) {		/* pcm interrupt */#ifdef ALI_DEBUG		outb((u8)(pvoice->number), ALI_REG(codec, ALI_GC_CIR));		temp = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));		cspf = (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask;#endif		if (pvoice->running) {			snd_ali_printk("update_ptr: cso=%4.4x cspf=%d.\n",(u16)temp,cspf);			spin_unlock(&codec->reg_lock);			snd_pcm_period_elapsed(pvoice->substream);			spin_lock(&codec->reg_lock);		} else {			snd_ali_stop_voice(codec, channel);			snd_ali_disable_voice_irq(codec, channel);		}		} else if (codec->synth.voices[channel].synth) {		/* synth interrupt */	} else if (codec->synth.voices[channel].midi) {		/* midi interrupt */	} else {		/* unknown interrupt */		snd_ali_stop_voice(codec, channel);		snd_ali_disable_voice_irq(codec, channel);	}	spin_unlock(&codec->reg_lock);	outl(mask,ALI_REG(codec,pchregs->regs.aint));	pchregs->data.aint = old & (~mask);}static void snd_ali_interrupt(ali_t * codec){	int channel;	unsigned int audio_int;	snd_ali_channel_control_t *pchregs = NULL;	pchregs = &(codec->chregs);	audio_int = inl(ALI_REG(codec, ALI_MISCINT));	if (audio_int & ADDRESS_IRQ) {		// get interrupt status for all channels		pchregs->data.aint = inl(ALI_REG(codec,pchregs->regs.aint));		for (channel = 0; channel < ALI_CHANNELS; channel++) {			snd_ali_update_ptr(codec, channel);		}	}	outl((TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),		ALI_REG(codec,ALI_MISCINT));}static irqreturn_t snd_ali_card_interrupt(int irq,				   void *dev_id,				   struct pt_regs *regs){	ali_t 	*codec = dev_id;	if (codec == NULL)		return IRQ_NONE;	snd_ali_interrupt(codec);	return IRQ_HANDLED;}static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec){	snd_ali_voice_t *pvoice = NULL;	unsigned long flags;	int idx;	snd_ali_printk("alloc_voice: type=%d rec=%d\n",type,rec);	spin_lock_irqsave(&codec->voice_alloc, flags);	if (type == SNDRV_ALI_VOICE_TYPE_PCM) {		idx = snd_ali_find_free_channel(codec,rec);		if(idx < 0) {			snd_printk("ali_alloc_voice: err.\n");			spin_unlock_irqrestore(&codec->voice_alloc, flags);			return NULL;		}		pvoice = &(codec->synth.voices[idx]);		pvoice->use = 1;		pvoice->pcm = 1;		pvoice->mode = rec;		spin_unlock_irqrestore(&codec->voice_alloc, flags);		return pvoice;	}	spin_unlock_irqrestore(&codec->voice_alloc, flags);	return NULL;}static void snd_ali_free_voice(ali_t * codec, snd_ali_voice_t *pvoice){	unsigned long flags;	void (*private_free)(void *);	void *private_data;	snd_ali_printk("free_voice: channel=%d\n",pvoice->number);	if (pvoice == NULL || !pvoice->use)		return;	snd_ali_clear_voices(codec, pvoice->number, pvoice->number);	spin_lock_irqsave(&codec->voice_alloc, flags);	private_free = pvoice->private_free;	private_data = pvoice->private_data;	pvoice->private_free = NULL;	pvoice->private_data = NULL;	if (pvoice->pcm) {		snd_ali_free_channel_pcm(codec, pvoice->number);	}	pvoice->use = pvoice->pcm = pvoice->synth = 0;	pvoice->substream = NULL;	spin_unlock_irqrestore(&codec->voice_alloc, flags);	if (private_free)		private_free(private_data);}static void snd_ali_clear_voices(ali_t * codec,			  unsigned int v_min,			  unsigned int v_max){	unsigned int i;	for (i = v_min; i <= v_max; i++) {		snd_ali_stop_voice(codec, i);		snd_ali_disable_voice_irq(codec, i);	}}static void snd_ali_write_voice_regs(ali_t * codec,			 unsigned int Channel,			 unsigned int LBA,			 unsigned int CSO,			 unsigned int ESO,			 unsigned int DELTA,			 unsigned int ALPHA_FMS,			 unsigned int GVSEL,			 unsigned int PAN,			 unsigned int VOL,			 unsigned int CTRL,			 unsigned int EC){	unsigned int ctlcmds[4];		outb((unsigned char)(Channel & 0x001f),ALI_REG(codec,ALI_GC_CIR));	ctlcmds[0] =  (CSO << 16) | (ALPHA_FMS & 0x0000ffff);	ctlcmds[1] =  LBA;	ctlcmds[2] =  (ESO << 16) | (DELTA & 0x0ffff);	ctlcmds[3] =  (GVSEL << 31) |		      ((PAN & 0x0000007f) << 24) |		      ((VOL & 0x000000ff) << 16) |

⌨️ 快捷键说明

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