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

📄 maestro.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Native play back driver  *//* the mode passed should be already shifted and masked */static void ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size){	u32 pa;	u32 tmpval;	int high_apu = 0;	int channel;	M_printk("mode=%d rate=%d buf=%p len=%d.\n",		mode, rate, buffer, size);			/* all maestro sizes are in 16bit words */	size >>=1;	if(mode&ESS_FMT_STEREO) {		high_apu++;		/* only 16/stereo gets size divided */		if(mode&ESS_FMT_16BIT)			size>>=1;	}		for(channel=0; channel <= high_apu; channel++)	{		pa = virt_to_bus(buffer);		/* set the wavecache control reg */		tmpval = (pa - 0x10) & 0xFFF8;		if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;		if(mode & ESS_FMT_STEREO) tmpval |= 2;		ess->apu_base[channel]=tmpval;		wave_set_register(ess, ess->apu[channel]<<3, tmpval);				pa -= virt_to_bus(ess->card->dmapages);		pa>>=1; /* words */				/* base offset of dma calcs when reading the pointer			on the left one */		if(!channel) ess->dma_dac.base = pa&0xFFFF;				pa|=0x00400000;			/* System RAM */		/* XXX the 16bit here might not be needed.. */		if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {			if(channel) 				pa|=0x00800000;			/* Stereo */			pa>>=1;		}			/* XXX think about endianess when writing these registers */		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);		/* start of sample */		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);		apu_set_register(ess, channel, 5, pa&0xFFFF);		/* sample end */		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);		/* setting loop len == sample len */		apu_set_register(ess, channel, 7, size);				/* clear effects/env.. */		apu_set_register(ess, channel, 8, 0x0000);		/* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */		apu_set_register(ess, channel, 9, 0xD000);		/* clear routing stuff */		apu_set_register(ess, channel, 11, 0x0000);		/* dma on, no envelopes, filter to all 1s) */		apu_set_register(ess, channel, 0, 0x400F);				if(mode&ESS_FMT_16BIT)			ess->apu_mode[channel]=0x10;		else			ess->apu_mode[channel]=0x30;		if(mode&ESS_FMT_STEREO) {			/* set panning: left or right */			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));			ess->apu_mode[channel] += 0x10;		} else			apu_set_register(ess, channel, 10, 0x8F08);	}		/* clear WP interrupts */	outw(1, ess->card->iobase+0x04);	/* enable WP ints */	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);	/* go team! */	set_dac_rate(ess,rate);	start_dac(ess);}/* *	Native record driver  *//* again, passed mode is alrady shifted/masked */static void ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size){	int apu_step = 2;	int channel;	M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",		mode, rate, buffer, size);			/* all maestro sizes are in 16bit words */	size >>=1;	/* we're given the full size of the buffer, but	in stereo each channel will only use its half */	if(mode&ESS_FMT_STEREO) {		size >>=1; 		apu_step = 1;	}		/* APU assignments: 2 = mono/left SRC	                    3 = right SRC	                    4 = mono/left Input Mixer	                    5 = right Input Mixer */	for(channel=2;channel<6;channel+=apu_step)	{		int i;		int bsize, route;		u32 pa;		u32 tmpval;		/* data seems to flow from the codec, through an apu into			the 'mixbuf' bit of page, then through the SRC apu			and out to the real 'buffer'.  ok.  sure.  */				if(channel & 0x04) {			/* ok, we're an input mixer going from adc				through the mixbuf to the other apus */			if(!(channel & 0x01)) { 				pa = virt_to_bus(ess->mixbuf);			} else {				pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));			}			/* we source from a 'magic' apu */			bsize = PAGE_SIZE >> 5;	/* half of this channels alloc, in words */			route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */			ess->apu_mode[channel] = 0x90;  /* Input Mixer */		} else {  			/* we're a rate converter taking				input from the input apus and outputing it to				system memory */			if(!(channel & 0x01))  {				pa = virt_to_bus(buffer);			} else {				/* right channel records its split half.				*2 accomodates for rampant shifting earlier */				pa = virt_to_bus(buffer + size*2);			}			ess->apu_mode[channel] = 0xB0;  /* Sample Rate Converter */			bsize = size; 			/* get input from inputing apu */			route = channel + 2;		}		M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);				/* set the wavecache control reg */		tmpval = (pa - 0x10) & 0xFFF8;		ess->apu_base[channel]=tmpval;		wave_set_register(ess, ess->apu[channel]<<3, tmpval);				pa -= virt_to_bus(ess->card->dmapages);		pa>>=1; /* words */				/* base offset of dma calcs when reading the pointer			on this left one */		if(channel==2) ess->dma_adc.base = pa&0xFFFF;		pa|=0x00400000;			/* bit 22 -> System RAM */		M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n", 			ess->apu[channel], pa, bsize, route);				/* Begin loading the APU */				for(i=0;i<15;i++)		/* clear all PBRs */			apu_set_register(ess, channel, i, 0x0000);					apu_set_register(ess, channel, 0, 0x400F);		/* need to enable subgroups.. and we should probably			have different groups for different /dev/dsps..  */ 		apu_set_register(ess, channel, 2, 0x8);						/* Load the buffer into the wave engine */		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);		/* XXX reg is little endian.. */		apu_set_register(ess, channel, 5, pa&0xFFFF);		apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);		apu_set_register(ess, channel, 7, bsize);						/* clear effects/env.. */		apu_set_register(ess, channel, 8, 0x00F0);				/* amplitude now?  sure.  why not.  */		apu_set_register(ess, channel, 9, 0x0000);		/* set filter tune, radius, polar pan */		apu_set_register(ess, channel, 10, 0x8F08);		/* route input */		apu_set_register(ess, channel, 11, route);	}		/* clear WP interrupts */	outw(1, ess->card->iobase+0x04);	/* enable WP ints */	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);	/* let 'er rip */	set_adc_rate(ess,rate);	start_adc(ess);}/* --------------------------------------------------------------------- */static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count){	M_printk("set_dmaa??\n");}static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count){	M_printk("set_dmac??\n");}/* Playback pointer */static inline unsigned get_dmaa(struct ess_state *s){	int offset;	offset = apu_get_register(s,0,5);/*	M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */		offset-=s->dma_dac.base;	return (offset&0xFFFE)<<1; /* hardware is in words */}/* Record pointer */static inline unsigned get_dmac(struct ess_state *s){	int offset;	offset = apu_get_register(s,2,5);/*	M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */		/* The offset is an address not a position relative to base */	offset-=s->dma_adc.base;		return (offset&0xFFFE)<<1; /* hardware is in words */}/* *	Meet Bob, the timer... */static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void stop_bob(struct ess_state *s){	/* Mask IDR 11,17 */	maestro_write(s,  0x11, maestro_read(s, 0x11)&~1);	maestro_write(s,  0x17, maestro_read(s, 0x17)&~1);}/* eventually we could be clever and limit bob ints	to the frequency at which our smallest duration	chunks may expire */#define ESS_SYSCLK	50000000static void start_bob(struct ess_state *s){	int prescale;	int divide;		/* XXX make freq selector much smarter, see calc_bob_rate */	int freq = 200; 		/* compute ideal interrupt frequency for buffer size & play rate */	/* first, find best prescaler value to match freq */	for(prescale=5;prescale<12;prescale++)		if(freq > (ESS_SYSCLK>>(prescale+9)))			break;				/* next, back off prescaler whilst getting divider into optimum range */	divide=1;	while((prescale > 5) && (divide<32))	{		prescale--;		divide <<=1;	}	divide>>=1;		/* now fine-tune the divider for best match */	for(;divide<31;divide++)		if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))			break;		/* divide = 0 is illegal, but don't let prescale = 4! */	if(divide == 0)	{		divide++;		if(prescale>5)			prescale--;	}	maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */		/* Now set IDR 11/17 */	maestro_write(s, 0x11, maestro_read(s, 0x11)|1);	maestro_write(s, 0x17, maestro_read(s, 0x17)|1);}/* --------------------------------------------------------------------- *//* this quickly calculates the frequency needed for bob	and sets it if its different than what bob is	currently running at.  its called often so 	needs to be fairly quick. */#define BOB_MIN 50#define BOB_MAX 400static void calc_bob_rate(struct ess_state *s) {#if 0 /* this thing tries to set the frequency of bob such that	there are 2 interrupts / buffer walked by the dac/adc.  That	is probably very wrong for people who actually care about 	mid buffer positioning.  it should be calculated as bytes/interrupt	and that needs to be decided :)  so for now just use the static 150	in start_bob.*/	unsigned int dac_rate=2,adc_rate=1,newrate;	static int israte=-1;	if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;	else  {		dac_rate =	(2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /				(s->dma_dac.fragsize) ;	}			if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;	else {		adc_rate =	(2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /				(s->dma_adc.fragsize) ;	}	if(dac_rate > adc_rate) newrate = adc_rate;	else newrate=dac_rate;	if(newrate > BOB_MAX) newrate = BOB_MAX;	else {		if(newrate < BOB_MIN) 			newrate = BOB_MIN;	}	if( israte != newrate) {		printk("dac: %d  adc: %d rate: %d\n",dac_rate,adc_rate,israte);		israte=newrate;	}#endif}static int prog_dmabuf(struct ess_state *s, unsigned rec){	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;	unsigned rate = rec ? s->rateadc : s->ratedac;	unsigned bytepersec;	unsigned bufs;	unsigned char fmt;	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	fmt = s->fmt;	if (rec) {		stop_adc(s);		fmt >>= ESS_ADC_SHIFT;	} else {		stop_dac(s);		fmt >>= ESS_DAC_SHIFT;	}	spin_unlock_irqrestore(&s->lock, flags);	fmt &= ESS_FMT_MASK;	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;	/* this algorithm is a little nuts.. where did /1000 come from? */	bytepersec = rate << sample_shift[fmt];	bufs = PAGE_SIZE << db->buforder;	if (db->ossfragshift) {		if ((1000 << db->ossfragshift) < bytepersec)			db->fragshift = ld2(bytepersec/1000);		else			db->fragshift = db->ossfragshift;	} else {		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));		if (db->fragshift < 3)			db->fragshift = 3; 	}	db->numfrag = bufs >> db->fragshift;	while (db->numfrag < 4 && db->fragshift > 3) {		db->fragshift--;		db->numfrag = bufs >> db->fragshift;	}	db->fragsize = 1 << db->fragshift;	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)		db->numfrag = db->ossmaxfrags;	db->fragsamples = db->fragsize >> sample_shift[fmt];	db->dmasize = db->numfrag << db->fragshift;	M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);	memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);	spin_lock_irqsave(&s->lock, flags);	if (rec) 		ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);	else 		ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);	spin_unlock_irqrestore(&s->lock, flags);	db->ready = 1;	return 0;}static __inline__ void clear_advance(struct ess_state *s){	unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;		unsigned char *buf = s->dma_dac.rawbuf;	unsigned bsize = s->dma_dac.dmasize;	unsigned bptr = s->dma_dac.swptr;	unsigned len = s->dma_dac.fragsize;		if (bptr + len > bsize) {

⌨️ 快捷键说明

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