trident.c

来自「linux 内核源代码」· C语言 代码 · 共 2,292 行 · 第 1/5 页

C
2,292
字号
{	int delta;	if (rate == 44100)		delta = 0x116a;	else if (rate == 8000)		delta = 0x6000;	else if (rate == 48000)		delta = 0x1000;	else		delta = ((48000 << 12) / rate) & 0x0000ffff;	return delta;}/* set playback sample rate */static unsigned inttrident_set_dac_rate(struct trident_state *state, unsigned int rate){	struct dmabuf *dmabuf = &state->dmabuf;	if (rate > 48000)		rate = 48000;	if (rate < 4000)		rate = 4000;	dmabuf->rate = rate;	dmabuf->channel->delta = compute_rate_play(rate);	trident_write_voice_regs(state);	pr_debug("trident: called trident_set_dac_rate : rate = %d\n", rate);	return rate;}/* set recording sample rate */static unsigned inttrident_set_adc_rate(struct trident_state *state, unsigned int rate){	struct dmabuf *dmabuf = &state->dmabuf;	if (rate > 48000)		rate = 48000;	if (rate < 4000)		rate = 4000;	dmabuf->rate = rate;	dmabuf->channel->delta = compute_rate_rec(rate);	trident_write_voice_regs(state);	pr_debug("trident: called trident_set_adc_rate : rate = %d\n", rate);	return rate;}/* prepare channel attributes for playback */static voidtrident_play_setup(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct trident_channel *channel = dmabuf->channel;	channel->lba = dmabuf->dma_handle;	channel->delta = compute_rate_play(dmabuf->rate);	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];	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;	pr_debug("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);	trident_write_voice_regs(state);}/* prepare channel attributes for recording */static voidtrident_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;	pr_debug("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);	trident_write_voice_regs(state);}/* get current playback/recording dma buffer pointer (byte offset from LBA),   called with spinlock held! */static inline unsignedtrident_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;	}	pr_debug("trident: trident_get_dma_addr: chip reported channel: %d, "		 "cso = 0x%04x\n", dmabuf->channel->num, cso);	/* 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 voidstop_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 voidstart_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 voidstop_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 voidstart_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/* alloc a DMA buffer of with a buffer of this order */static intalloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev, int order){	void *rawbuf = NULL;	struct page *page, *pend;	if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,					    &dmabuf->dma_handle)))		return -ENOMEM;	pr_debug("trident: allocated %ld (order = %d) bytes at %p\n",		 PAGE_SIZE << order, order, rawbuf);	dmabuf->ready = dmabuf->mapped = 0;	dmabuf->rawbuf = rawbuf;	dmabuf->buforder = order;	/* now mark the pages as reserved; otherwise */	/* remap_pfn_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++)		SetPageReserved(page);	return 0;}/* allocate the main DMA buffer, playback and recording buffer should be *//* allocated separately */static intalloc_main_dmabuf(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	int order;	int ret = -ENOMEM;	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {		if (!(ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order)))			return 0;		/* else try again */	}	return ret;}/* deallocate a DMA buffer */static voiddealloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev){	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++)			ClearPageReserved(page);		pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,				    dmabuf->rawbuf, dmabuf->dma_handle);		dmabuf->rawbuf = NULL;	}	dmabuf->mapped = dmabuf->ready = 0;}static intprog_dmabuf(struct trident_state *state, enum dmabuf_mode rec){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned bytepersec;	struct trident_state *s = state;	unsigned bufsize, dma_nums;	unsigned long flags;	int ret, i, order;	if ((ret = lock_set_fmt(state)) < 0)		return ret;	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_main_dmabuf(state))) {					unlock_set_fmt(state);					return ret;				}			} else {				ret = -ENOMEM;				order = state->dmabuf.buforder - 1;				if (order >= DMABUF_MINORDER) {					ret = alloc_dmabuf(dmabuf,							   state->card->pci_dev,							   order);				}				if (ret) {					/* release the main DMA buffer */					dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);					/* release the auxiliary DMA buffers */					for (i -= 2; i >= 0; i--)						dealloc_dmabuf(&state->other_states[i]->dmabuf,							       state->card->pci_dev);					unlock_set_fmt(state);					return ret;				}			}		}

⌨️ 快捷键说明

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