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

📄 cmpci.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (s->chip_version == 33)			maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);		if (s->chip_version >= 39)			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);		s->status &= ~DO_AC3;	}	s->spdif_counter = 0;}static void set_line_as_rear(struct cm_state *s, int use_line_as_rear){	if (!(s->capability & CAN_LINE_AS_REAR))		return;	if (use_line_as_rear) {		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);		s->status |= DO_LINE_AS_REAR;	} else {		maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);		s->status &= ~DO_LINE_AS_REAR;	}}static void set_line_as_bass(struct cm_state *s, int use_line_as_bass){	if (!(s->capability & CAN_LINE_AS_BASS))		return;	if (use_line_as_bass) {		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);		s->status |= DO_LINE_AS_BASS;	} else {		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);		s->status &= ~DO_LINE_AS_BASS;	}}static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass){	if (!(s->capability & CAN_MIC_AS_BASS))		return;	if (use_mic_as_bass) {		maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);		s->status |= DO_MIC_AS_BASS;	} else {		maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);		s->status &= ~DO_MIC_AS_BASS;	}}static void set_hw_copy(struct cm_state *s, int hw_copy){    	if (s->max_channels > 2 && hw_copy)		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);    	else		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);}static void set_ac3(struct cm_state *s, unsigned rate){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	set_spdifout_unlocked(s, rate);	set_ac3_unlocked(s, rate);	spin_unlock_irqrestore(&s->lock, flags);}static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size){	int   i = size / 2;	unsigned long data;	unsigned short data16;	unsigned long *dst = (unsigned long *) dest;	unsigned short __user *src = (unsigned short __user *)source;	int err;	do {		if ((err = __get_user(data16, src++)))			return err;		data = (unsigned long)le16_to_cpu(data16);		data <<= 12;			// ok for 16-bit data		if (s->spdif_counter == 2 || s->spdif_counter == 3)			data |= 0x40000000;	// indicate AC-3 raw data		if (parity(data))			data |= 0x80000000;	// parity		if (s->spdif_counter == 0)			data |= 3;		// preamble 'M'		else if (s->spdif_counter & 1)			data |= 5;		// odd, 'W'		else			data |= 9;		// even, 'M'		*dst++ = cpu_to_le32(data);		s->spdif_counter++;		if (s->spdif_counter == 384)			s->spdif_counter = 0;	} while (--i);	return 0;}static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate){	unsigned char freq = 4;	int	i;	if (rate > 48000)		rate = 48000;	if (rate < 8000)		rate = 8000;	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {			rate = rate_lookup[i].rate;			freq = rate_lookup[i].freq;			break;	    	}	}	s->rateadc = rate;	freq <<= CM_FREQ_ADCSHIFT;	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);}static void set_adc_rate(struct cm_state *s, unsigned rate){	unsigned long flags;	unsigned char freq = 4;	int	i;	if (rate > 48000)		rate = 48000;	if (rate < 8000)		rate = 8000;	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {			rate = rate_lookup[i].rate;			freq = rate_lookup[i].freq;			break;	    	}	}	s->rateadc = rate;	freq <<= CM_FREQ_ADCSHIFT;	spin_lock_irqsave(&s->lock, flags);	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);	spin_unlock_irqrestore(&s->lock, flags);}static void set_dac_rate(struct cm_state *s, unsigned rate){	unsigned long flags;	unsigned char freq = 4;	int	i;	if (rate > 48000)		rate = 48000;	if (rate < 8000)		rate = 8000;	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {			rate = rate_lookup[i].rate;			freq = rate_lookup[i].freq;			break;	    	}	}	s->ratedac = rate;	freq <<= CM_FREQ_DACSHIFT;	spin_lock_irqsave(&s->lock, flags);	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);	spin_unlock_irqrestore(&s->lock, flags);	if (s->curr_channels <= 2 && spdif_out)		set_spdifout(s, rate);	if (s->status & DO_DUAL_DAC)		set_dac1_rate(s, rate);}/* --------------------------------------------------------------------- */static inline void reset_adc(struct cm_state *s){	/* reset bus master */	outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	udelay(10);	outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);}static inline void reset_dac(struct cm_state *s){	/* reset bus master */	outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	udelay(10);	outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	if (s->status & DO_DUAL_DAC)		reset_adc(s);}static inline void pause_adc(struct cm_state *s){	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);}static inline void pause_dac(struct cm_state *s){	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);	if (s->status & DO_DUAL_DAC)		pause_adc(s);}static inline void disable_adc(struct cm_state *s){	/* disable channel */	s->enable &= ~ENADC;	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	reset_adc(s);}static inline void disable_dac(struct cm_state *s){	/* disable channel */	s->enable &= ~ENDAC;	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	reset_dac(s);	if (s->status & DO_DUAL_DAC)		disable_adc(s);}static inline void enable_adc(struct cm_state *s){	if (!(s->enable & ENADC)) {		/* enable channel */		s->enable |= ENADC;		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	}	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);}static inline void enable_dac_unlocked(struct cm_state *s){	if (!(s->enable & ENDAC)) {		/* enable channel */		s->enable |= ENDAC;		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	}	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);	if (s->status & DO_DUAL_DAC)		enable_adc(s);}static inline void enable_dac(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	enable_dac_unlocked(s);	spin_unlock_irqrestore(&s->lock, flags);}static inline void stop_adc_unlocked(struct cm_state *s){	if (s->enable & ENADC) {		/* disable interrupt */		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);		disable_adc(s);	}}static inline void stop_adc(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	stop_adc_unlocked(s);	spin_unlock_irqrestore(&s->lock, flags);}static inline void stop_dac_unlocked(struct cm_state *s){	if (s->enable & ENDAC) {		/* disable interrupt */		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);		disable_dac(s);	}	if (s->status & DO_DUAL_DAC)		stop_dac1_unlocked(s);}static inline void stop_dac(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	stop_dac_unlocked(s);	spin_unlock_irqrestore(&s->lock, flags);}static inline void start_adc_unlocked(struct cm_state *s){	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))	    && s->dma_adc.ready) {		/* enable interrupt */		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);		enable_adc(s);	}}static void start_adc(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	start_adc_unlocked(s);	spin_unlock_irqrestore(&s->lock, flags);}static void start_dac1_unlocked(struct cm_state *s){	if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {		/* enable interrupt */		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT); 		enable_dac_unlocked(s);	}}static void start_dac_unlocked(struct cm_state *s){	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {		/* enable interrupt */		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);		enable_dac_unlocked(s);	}	if (s->status & DO_DUAL_DAC)		start_dac1_unlocked(s);}static void start_dac(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	start_dac_unlocked(s);	spin_unlock_irqrestore(&s->lock, flags);}static int prog_dmabuf(struct cm_state *s, unsigned rec);static int set_dac_channels(struct cm_state *s, int channels){	unsigned long flags;	static unsigned int fmmute = 0;	spin_lock_irqsave(&s->lock, flags);	if ((channels > 2) && (channels <= s->max_channels)	 && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {	    set_spdifout_unlocked(s, 0);	    if (s->capability & CAN_MULTI_CH_HW) {		// NXCHG		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);		// CHB3D or CHB3D5C	       	maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);		// CHB3D6C		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);		// ENCENTER		maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);		s->status |= DO_MULTI_CH_HW;	    } else if (s->capability & CAN_DUAL_DAC) {		unsigned char fmtm = ~0, fmts = 0;		ssize_t ret;		// ENDBDAC, turn on double DAC mode		// XCHGDAC, CH0 -> back, CH1->front		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);		// mute FM		fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE;		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE);		s->status |= DO_DUAL_DAC;		// prepare secondary buffer		spin_unlock_irqrestore(&s->lock, flags);		ret = prog_dmabuf(s, 1);		if (ret) return ret;		spin_lock_irqsave(&s->lock, flags);		// copy the hw state		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);		// the HW only support 16-bit stereo		fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;		fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;		fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;		fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;		set_fmt_unlocked(s, fmtm, fmts);		set_adc_rate_unlocked(s, s->ratedac);	    }	    // disable 4 speaker mode (analog duplicate)	    set_hw_copy(s, 0);	    s->curr_channels = channels;	    // enable jack redirect	    set_line_as_rear(s, use_line_as_rear);	    if (channels > 4) {		    set_line_as_bass(s, use_line_as_bass);		    set_mic_as_bass(s, use_mic_as_bass);	    }	} else {	    if (s->status & DO_MULTI_CH_HW) {		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);		maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);	    } else if (s->status & DO_DUAL_DAC) {		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);		maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute);	    }	    // enable 4 speaker mode (analog duplicate)	    set_hw_copy(s, hw_copy);	    s->status &= ~DO_MULTI_CH;	    s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;	    // disable jack redirect	    set_line_as_rear(s, hw_copy ? use_line_as_rear : 0);	    set_line_as_bass(s, 0);	    set_mic_as_bass(s, 0);	}	spin_unlock_irqrestore(&s->lock, flags);	return s->curr_channels;}/* --------------------------------------------------------------------- */#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)#define DMABUF_MINORDER 1static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db){	struct page *pstart, *pend;	if (db->rawbuf) {		/* undo marking the pages as reserved */		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)			ClearPageReserved(pstart);		pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);	}	db->rawbuf = NULL;	db->mapped = db->ready = 0;}/* Ch1 is used for playback, Ch0 is used for recording */static int prog_dmabuf(struct cm_state *s, unsigned rec){	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;	unsigned rate = rec ? s->rateadc : s->ratedac;	int order;	unsigned bytepersec;	unsigned bufs;	struct page *pstart, *pend;	unsigned char fmt;

⌨️ 快捷键说明

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