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

📄 trident.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	channel->eso -= 1;	if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {		channel->attribute = 0;		if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) {			if ((channel->num == ALI_SPDIF_IN_CHANNEL) || (channel->num == ALI_PCM_IN_CHANNEL))				ali_disable_special_channel(state->card, channel->num);			else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE) 								&& (channel->num == ALI_SPDIF_OUT_CHANNEL))			{				ali_set_spdif_out_rate(state->card, state->dmabuf.rate);				state->dmabuf.channel->delta = 0x1000;			}		}	}	channel->fm_vol = 0x0;		channel->control = CHANNEL_LOOP;	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {		/* 16-bits */		channel->control |= CHANNEL_16BITS;		/* signed */		channel->control |= CHANNEL_SIGNED;	}	if (dmabuf->fmt & TRIDENT_FMT_STEREO)		/* stereo */		channel->control |= CHANNEL_STEREO;#ifdef DEBUG	printk("trident: trident_play_setup, LBA = 0x%08x, "	       "Delta = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",	       channel->lba, channel->delta, channel->eso, channel->control);#endif	trident_write_voice_regs(state);}/* prepare channel attributes for recording */static void trident_rec_setup(struct trident_state *state){	u16 w;	u8  bval;	struct trident_card *card = state->card;	struct dmabuf *dmabuf = &state->dmabuf;	struct trident_channel *channel = dmabuf->channel;	unsigned int rate;	/* Enable AC-97 ADC (capture) */	switch (card->pci_id) 	{	case PCI_DEVICE_ID_ALI_5451:		ali_enable_special_channel(state);		break;	case PCI_DEVICE_ID_SI_7018:		/* for 7018, the ac97 is always in playback/record (duplex) mode */		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:		w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));		outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));		/* enable and set record channel */		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:		w = inw(TRID_REG(card, T4D_MISCINT));		outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));		/* enable and set record channel */		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));		break;	case PCI_DEVICE_ID_INTERG_5050:		/* don't know yet, using special channel 22 in GC1(0xd4)? */		break;	default:		return;	}	channel->lba = dmabuf->dma_handle;	channel->delta = compute_rate_rec(dmabuf->rate);	if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) {		rate = ali_get_spdif_in_rate(card);		if (rate == 0)		{			printk(KERN_WARNING "trident: ALi 5451 S/PDIF input setup error!\n");			rate = 48000;		}		bval = inb(TRID_REG(card,ALI_SPDIF_CTRL));		if (bval & 0x10)		{			outb(bval,TRID_REG(card,ALI_SPDIF_CTRL));			printk(KERN_WARNING "trident: cleared ALi 5451 S/PDIF parity error flag.\n");		}		if (rate != 48000)			channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff;	}		channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];	channel->eso -= 1;	if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {		channel->attribute = 0;	}	channel->fm_vol = 0x0;		channel->control = CHANNEL_LOOP;	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {		/* 16-bits */		channel->control |= CHANNEL_16BITS;		/* signed */		channel->control |= CHANNEL_SIGNED;	}	if (dmabuf->fmt & TRIDENT_FMT_STEREO)		/* stereo */		channel->control |= CHANNEL_STEREO;#ifdef DEBUG	printk("trident: trident_rec_setup, LBA = 0x%08x, "	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",	       channel->lba, channel->delta, channel->eso, channel->control);#endif	trident_write_voice_regs(state);}/* get current playback/recording dma buffer pointer (byte offset from LBA),   called with spinlock held! */static inline unsigned trident_get_dma_addr(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	u32 cso;	if (!dmabuf->enable)		return 0;	outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR));	switch (state->card->pci_id) 	{	case PCI_DEVICE_ID_ALI_5451:	case PCI_DEVICE_ID_SI_7018:	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:	case PCI_DEVICE_ID_INTERG_5050:		/* 16 bits ESO, CSO for 7018 and DX */		cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2));		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:		/* 24 bits ESO, CSO for NX */		cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff;		break;	default:		return 0;	}#ifdef DEBUG	printk("trident: trident_get_dma_addr: chip reported channel: %d, "	       "cso = 0x%04x\n",	       dmabuf->channel->num, cso);#endif	/* ESO and CSO are in units of Samples, convert to byte offset */	cso <<= sample_shift[dmabuf->fmt];	return (cso % dmabuf->dmasize);}/* Stop recording (lock held) */static inline void __stop_adc(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned int chan_num = dmabuf->channel->num;	struct trident_card *card = state->card;	dmabuf->enable &= ~ADC_RUNNING;	trident_stop_voice(card, chan_num);	trident_disable_voice_irq(card, chan_num);}static void stop_adc(struct trident_state *state){	struct trident_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__stop_adc(state);	spin_unlock_irqrestore(&card->lock, flags);}static void start_adc(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned int chan_num = dmabuf->channel->num;	struct trident_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {		dmabuf->enable |= ADC_RUNNING;		trident_enable_voice_irq(card, chan_num);		trident_start_voice(card, chan_num);	}	spin_unlock_irqrestore(&card->lock, flags);}/* stop playback (lock held) */static inline void __stop_dac(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned int chan_num = dmabuf->channel->num;	struct trident_card *card = state->card;	dmabuf->enable &= ~DAC_RUNNING;	trident_stop_voice(card, chan_num);	if (state->chans_num == 6) {		trident_stop_voice(card, state->other_states[0]->dmabuf.channel->num);		trident_stop_voice(card, state->other_states[1]->dmabuf.channel->num);		trident_stop_voice(card, state->other_states[2]->dmabuf.channel->num);		trident_stop_voice(card, state->other_states[3]->dmabuf.channel->num);	}	trident_disable_voice_irq(card, chan_num);}static void stop_dac(struct trident_state *state){	struct trident_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__stop_dac(state);	spin_unlock_irqrestore(&card->lock, flags);}	static void start_dac(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned int chan_num = dmabuf->channel->num;	struct trident_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {		dmabuf->enable |= DAC_RUNNING;		trident_enable_voice_irq(card, chan_num);		trident_start_voice(card, chan_num);		if (state->chans_num == 6) {			trident_start_voice(card, state->other_states[0]->dmabuf.channel->num);			trident_start_voice(card, state->other_states[1]->dmabuf.channel->num);			trident_start_voice(card, state->other_states[2]->dmabuf.channel->num);			trident_start_voice(card, state->other_states[3]->dmabuf.channel->num);		}	}	spin_unlock_irqrestore(&card->lock, flags);}#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)#define DMABUF_MINORDER 1/* allocate DMA buffer, playback and recording buffer should be allocated seperately */static int alloc_dmabuf(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	void *rawbuf = NULL;	int order;	struct page *page, *pend;	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,						   PAGE_SIZE << order,						   &dmabuf->dma_handle)))			break;	if (!rawbuf)		return -ENOMEM;#ifdef DEBUG	printk("trident: allocated %ld (order = %d) bytes at %p\n",	       PAGE_SIZE << order, order, rawbuf);#endif	dmabuf->ready  = dmabuf->mapped = 0;	dmabuf->rawbuf = rawbuf;	dmabuf->buforder = order;		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);	for (page = virt_to_page(rawbuf); page <= pend; page++)		mem_map_reserve(page);	return 0;}/* free DMA buffer */static void dealloc_dmabuf(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct page *page, *pend;	if (dmabuf->rawbuf) {		/* undo marking the pages as reserved */		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)			mem_map_unreserve(page);		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,				    dmabuf->rawbuf, dmabuf->dma_handle);	}	dmabuf->rawbuf = NULL;	dmabuf->mapped = dmabuf->ready = 0;}static int prog_dmabuf(struct trident_state *state, unsigned rec){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned bytepersec;	struct trident_state *s = state;	unsigned bufsize, dma_nums;	unsigned long flags;	int ret, i, order;	struct page *page, *pend;		lock_set_fmt(state);	if (state->chans_num == 6)		dma_nums = 5;	else 	dma_nums = 1;		for (i = 0; i < dma_nums; i++) {		if (i > 0) {			s = state->other_states[i - 1];						dmabuf = &s->dmabuf;			dmabuf->fmt = state->dmabuf.fmt;			dmabuf->rate = state->dmabuf.rate;		}		spin_lock_irqsave(&s->card->lock, flags);		dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;		dmabuf->count = dmabuf->error = 0;		spin_unlock_irqrestore(&s->card->lock, flags);		/* allocate DMA buffer if not allocated yet */		if (!dmabuf->rawbuf) {			if (i == 0) {				if ((ret = alloc_dmabuf(state))) {					unlock_set_fmt(state);					return ret;				}			}			else {				if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) {					dmabuf->rawbuf = pci_alloc_consistent(state->card->pci_dev,									      PAGE_SIZE << order,									      &dmabuf->dma_handle);				}				if (!dmabuf->rawbuf) {					free_pages((unsigned long)state->dmabuf.rawbuf, state->dmabuf.buforder);					state->dmabuf.rawbuf = NULL;					i-=2;					for (; i >= 0; i--) {						pci_free_consistent(state->card->pci_dev,								    PAGE_SIZE << state->other_states[i]->dmabuf.buforder,								    state->other_states[i]->dmabuf.rawbuf,								    state->other_states[i]->dmabuf.dma_handle);					}					unlock_set_fmt(state);					return -ENOMEM;				}				dmabuf->ready  = dmabuf->mapped = 0;				dmabuf->buforder = order;				pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << order) - 1);				for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)					mem_map_reserve(page);			}		}		/* FIXME: figure out all this OSS fragment stuff */		bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];		bufsize = PAGE_SIZE << dmabuf->buforder;		if (dmabuf->ossfragshift) {			if ((1000 << dmabuf->ossfragshift) < bytepersec)				dmabuf->fragshift = ld2(bytepersec/1000);			else				dmabuf->fragshift = dmabuf->ossfragshift;		} else {			/* lets hand out reasonable big ass buffers by default */			dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);		}		dmabuf->numfrag = bufsize >> dmabuf->fragshift;		while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {			dmabuf->fragshift--;			dmabuf->numfrag = bufsize >> dmabuf->fragshift;		}		dmabuf->fragsize = 1 << dmabuf->fragshift;		if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)			dmabuf->numfrag = dmabuf->ossmaxfrags;		dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];		dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;		memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,		       dmabuf->dmasize);		spin_lock_irqsave(&s->card->lock, flags);		if (rec) {			trident_rec_setup(s);		} else {			trident_play_setup(s);		}		spin_unlock_irqrestore(&s->card->lock, flags);		/* set the ready flag for the dma buffer */		dmabuf->ready = 1;#ifdef DEBUG	printk("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, "	       "fragsize = %d dmasize = %d\n",	       dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,	       dmabuf->fragsize, dmabuf->dmasize);#endif	}	unlock_set_fmt(state);	return 0;}/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.   |------------|------------|   or   |xxxxxxxxxxxx|------------|   or   |xxxxxxxxxxxx|xxxxxxxxxxxx|   but we almost always get this   |xxxxxx------|------------|   or   |xxxxxxxxxxxx|xxxxx-------|   so we have to clear the tail space to "silence"   |xxxxxx000000|------------|   or   |xxxxxxxxxxxx|xxxxxx000000|*/static void trident_clear_tail(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned swptr;	unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;	unsigned int len;	unsigned long flags;	spin_lock_irqsave(&state->card->lock, flags);	swptr = dmabuf->swptr;	spin_unlock_irqrestore(&state->card->lock, flags);	if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)		return;	if (swptr < dmabuf->dmasize/2)		len = dmabuf->dmasize/2 - swptr;	else		len = dmabuf->dmasize - swptr;	memset(dmabuf->rawbuf + swptr, silence, len);	if(state->card->pci_id != PCI_DEVICE_ID_ALI_5451)	{		spin_lock_irqsave(&state->card->lock, flags);		dmabuf->swptr += len;		dmabuf->count += len;		spin_unlock_irqrestore(&state->card->lock, flags);	}

⌨️ 快捷键说明

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