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

📄 maestro.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	maestro_ac97_set(iobase, 0x1C, 0x0000);	maestro_ac97_set(iobase, 0x02, 0x0404);	maestro_ac97_set(iobase, 0x04, 0x0808);	maestro_ac97_set(iobase, 0x0C, 0x801F);	maestro_ac97_set(iobase, 0x0E, 0x801F);	return 0;}#endif/* this is very magic, and very slow.. */static void maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev){	u16 save_68;	u16 w;	u32 vend;	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);	/* reset the first codec */	outw(0x0000,  ioaddr+0x36);	save_68 = inw(ioaddr+0x68);	pci_read_config_word(pcidev, 0x58, &w);	/* something magical with gpio and bus arb. */	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);	if( w & 0x1)		save_68 |= 0x10;	outw(0xfffe, ioaddr + 0x64);	/* tickly gpio 0.. */	outw(0x0001, ioaddr + 0x68);	outw(0x0000, ioaddr + 0x60);	udelay(20);	outw(0x0001, ioaddr + 0x60);	mdelay(20);	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */	outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);	outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);	outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);	/* now the second codec */	outw(0x0000,  ioaddr+0x36);	outw(0xfff7, ioaddr + 0x64);	save_68 = inw(ioaddr+0x68);	outw(0x0009, ioaddr + 0x68);	outw(0x0001, ioaddr + 0x60);	udelay(20);	outw(0x0009, ioaddr + 0x60);	mdelay(500);	/* .. ouch.. */	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);#if 0 /* the loop here needs to be much better if we want it.. */	M_printk("trying software reset\n");	/* try and do a software reset */	outb(0x80|0x7c, ioaddr + 0x30);	for (w=0; ; w++) {		if ((inw(ioaddr+ 0x30) & 1) == 0) {			if(inb(ioaddr + 0x32) !=0) break;			outb(0x80|0x7d, ioaddr + 0x30);			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;			outb(0x80|0x7f, ioaddr + 0x30);			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;		}		if( w > 10000) {			outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);  /* do a software reset */			mdelay(500); /* oh my.. */			outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);  			udelay(1);			outw( 0x80, ioaddr+0x30);			for(w = 0 ; w < 10000; w++) {				if((inw(ioaddr + 0x30) & 1) ==0) break;			}		}	}#endif	if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {		/* turn on external amp? */		outw(0xf9ff, ioaddr + 0x64);		outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);		outw(0x0209, ioaddr + 0x60);	}	/* Turn on the 978 docking chip.	   First frob the "master output enable" bit,	   then set most of the playback volume control registers to max. */	outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);	outb(0xff, ioaddr+0xc3);	outb(0xff, ioaddr+0xc4);	outb(0xff, ioaddr+0xc6);	outb(0xff, ioaddr+0xc8);	outb(0x3f, ioaddr+0xcf);	outb(0x3f, ioaddr+0xd0);}/* *	Indirect register access. Not all registers are readable so we *	need to keep register state ourselves */ #define WRITEABLE_MAP	0xEFFFFF#define READABLE_MAP	0x64003F/* *	The Maestro engineers were a little indirection happy. These indirected *	registers themselves include indirect registers at another layer */static void __maestro_write(struct ess_card *card, u16 reg, u16 data){	long ioaddr = card->iobase;	outw(reg, ioaddr+0x02);	outw(data, ioaddr+0x00);	if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);	else card->maestro_map[reg]=data;} static void maestro_write(struct ess_state *s, u16 reg, u16 data){	unsigned long flags;	check_suspend(s->card);	spin_lock_irqsave(&s->card->lock,flags);	__maestro_write(s->card,reg,data);	spin_unlock_irqrestore(&s->card->lock,flags);}static u16 __maestro_read(struct ess_card *card, u16 reg){	long ioaddr = card->iobase;	outw(reg, ioaddr+0x02);	return card->maestro_map[reg]=inw(ioaddr+0x00);}static u16 maestro_read(struct ess_state *s, u16 reg){	if(READABLE_MAP & (1<<reg))	{		unsigned long flags;		check_suspend(s->card);		spin_lock_irqsave(&s->card->lock,flags);		__maestro_read(s->card,reg);		spin_unlock_irqrestore(&s->card->lock,flags);	}	return s->card->maestro_map[reg];}/* *	These routines handle accessing the second level indirections to the *	wave ram. *//* *	The register names are the ones ESS uses (see 104T31.ZIP) */ #define IDR0_DATA_PORT		0x00#define IDR1_CRAM_POINTER	0x01#define IDR2_CRAM_DATA		0x02#define IDR3_WAVE_DATA		0x03#define IDR4_WAVE_PTR_LOW	0x04#define IDR5_WAVE_PTR_HI	0x05#define IDR6_TIMER_CTRL		0x06#define IDR7_WAVE_ROMRAM	0x07static void apu_index_set(struct ess_card *card, u16 index){	int i;	__maestro_write(card, IDR1_CRAM_POINTER, index);	for(i=0;i<1000;i++)		if(__maestro_read(card, IDR1_CRAM_POINTER)==index)			return;	printk(KERN_WARNING "maestro: APU register select failed.\n");}static void apu_data_set(struct ess_card *card, u16 data){	int i;	for(i=0;i<1000;i++)	{		if(__maestro_read(card, IDR0_DATA_PORT)==data)			return;		__maestro_write(card, IDR0_DATA_PORT, data);	}}/* *	This is the public interface for APU manipulation. It handles the *	interlock to avoid two APU writes in parallel etc. Don't diddle *	directly with the stuff above. */static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data){	unsigned long flags;		check_suspend(s->card);	if(channel&ESS_CHAN_HARD)		channel&=~ESS_CHAN_HARD;	else	{		if(channel>5)			printk("BAD CHANNEL %d.\n",channel);		else			channel = s->apu[channel];		/* store based on real hardware apu/reg */		s->card->apu_map[channel][reg]=data;	}	reg|=(channel<<4);		/* hooray for double indirection!! */	spin_lock_irqsave(&s->card->lock,flags);	apu_index_set(s->card, reg);	apu_data_set(s->card, data);	spin_unlock_irqrestore(&s->card->lock,flags);}static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg){	unsigned long flags;	u16 v;		check_suspend(s->card);	if(channel&ESS_CHAN_HARD)		channel&=~ESS_CHAN_HARD;	else		channel = s->apu[channel];	reg|=(channel<<4);		spin_lock_irqsave(&s->card->lock,flags);	apu_index_set(s->card, reg);	v=__maestro_read(s->card, IDR0_DATA_PORT);	spin_unlock_irqrestore(&s->card->lock,flags);	return v;}/* *	The wavecache buffers between the APUs and *	pci bus mastering */ static void wave_set_register(struct ess_state *s, u16 reg, u16 value){	long ioaddr = s->card->iobase;	unsigned long flags;	check_suspend(s->card);		spin_lock_irqsave(&s->card->lock,flags);	outw(reg, ioaddr+0x10);	outw(value, ioaddr+0x12);	spin_unlock_irqrestore(&s->card->lock,flags);}static u16 wave_get_register(struct ess_state *s, u16 reg){	long ioaddr = s->card->iobase;	unsigned long flags;	u16 value;	check_suspend(s->card);		spin_lock_irqsave(&s->card->lock,flags);	outw(reg, ioaddr+0x10);	value=inw(ioaddr+0x12);	spin_unlock_irqrestore(&s->card->lock,flags);		return value;}static void sound_reset(int ioaddr){	outw(0x2000, 0x18+ioaddr);	udelay(1);	outw(0x0000, 0x18+ioaddr);	udelay(1);}/* sets the play formats of these apus, should be passed the already shifted format */static void set_apu_fmt(struct ess_state *s, int apu, int mode){	int apu_fmt = 0x10;	if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 	if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 	s->apu_mode[apu]   = apu_fmt;	s->apu_mode[apu+1] = apu_fmt;}/* this only fixes the output apu mode to be later set by start_dac and	company.  output apu modes are set in ess_rec_setup */static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data){	s->fmt = (s->fmt & mask) | data;	set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);}/* this is off by a little bit.. */static u32 compute_rate(struct ess_state *s, u32 freq){	u32 clock = clock_freq[s->card->card_type];     	freq = (freq * clocking)/48000;		if (freq == 48000) 		return 0x10000;	return ((freq / clock) <<16 )+  		(((freq % clock) << 16) / clock);}static void set_dac_rate(struct ess_state *s, unsigned int rate){	u32 freq;	int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;	if (rate > 48000)		rate = 48000;	if (rate < 4000)		rate = 4000;	s->ratedac = rate;	if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))		rate >>= 1;/*	M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/	freq = compute_rate(s, rate);		/* Load the frequency, turn on 6dB */	apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 0, 3, freq>>8);	apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 1, 3, freq>>8);}static void set_adc_rate(struct ess_state *s, unsigned rate){	u32 freq;	/* Sample Rate conversion APUs don't like 0x10000 for their rate */	if (rate > 47999)		rate = 47999;	if (rate < 4000)		rate = 4000;	s->rateadc = rate;	freq = compute_rate(s, rate);		/* Load the frequency, turn on 6dB */	apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 2, 3, freq>>8);	apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 3, 3, freq>>8);	/* fix mixer rate at 48khz.  and its _must_ be 0x10000. */	freq = 0x10000;	apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 4, 3, freq>>8);	apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|		( ((freq&0xFF)<<8)|0x10 ));	apu_set_register(s, 5, 3, freq>>8);}/* Stop our host of recording apus */static inline void stop_adc(struct ess_state *s){	/* XXX lets hope we don't have to lock around this */	if (! (s->enable & ADC_RUNNING)) return;	s->enable &= ~ADC_RUNNING;	apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);	apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);	apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);	apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);}	/* stop output apus */static void stop_dac(struct ess_state *s){	/* XXX have to lock around this? */	if (! (s->enable & DAC_RUNNING)) return;	s->enable &= ~DAC_RUNNING;	apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);	apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);}	static void start_dac(struct ess_state *s){	/* XXX locks? */	if (	(s->dma_dac.mapped || s->dma_dac.count > 0) && 		s->dma_dac.ready &&		(! (s->enable & DAC_RUNNING)) ) {		s->enable |= DAC_RUNNING;		apu_set_register(s, 0, 0, 			(apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);		if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) 			apu_set_register(s, 1, 0, 				(apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);	}}	static void start_adc(struct ess_state *s){	/* XXX locks? */	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 	    && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {		s->enable |= ADC_RUNNING;		apu_set_register(s, 2, 0, 			(apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);		apu_set_register(s, 4, 0, 			(apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);		if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {			apu_set_register(s, 3, 0, 				(apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);			apu_set_register(s, 5, 0, 				(apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);		}				}}	

⌨️ 快捷键说明

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