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

📄 cmpci.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
#define	DO_MULTI_CH		(DO_MULTI_CH_HW | DO_DUAL_DAC)#define	DO_LINE_AS_REAR		0x00000010		/* 033 or later */#define	DO_LINE_AS_BASS		0x00000020		/* 039 or later */#define	DO_MIC_AS_BASS		0x00000040		/* 039 or later */#define	DO_SPDIF_OUT		0x00000100#define	DO_SPDIF_IN		0x00000200#define	DO_SPDIF_LOOP		0x00000400#define	DO_BIGENDIAN_W		0x00001000		/* used in PowerPC */#define	DO_BIGENDIAN_R		0x00002000		/* used in PowerPC */static LIST_HEAD(devs);static	int	mpuio = 0;static	int	fmio = 0;static	int	joystick = 0;static	int	spdif_inverse = 0;static	int	spdif_loop = 0;static	int	spdif_out = 0;static	int	use_line_as_rear = 0;static	int	use_line_as_bass = 0;static	int	use_mic_as_bass = 0;static	int	mic_boost = 0;static	int	hw_copy = 0;MODULE_PARM(mpuio, "i");MODULE_PARM(fmio, "i");MODULE_PARM(joystick, "i");MODULE_PARM(spdif_inverse, "i");MODULE_PARM(spdif_loop, "i");MODULE_PARM(spdif_out, "i");MODULE_PARM(use_line_as_rear, "i");MODULE_PARM(use_line_as_bass, "i");MODULE_PARM(use_mic_as_bass, "i");MODULE_PARM(mic_boost, "i");MODULE_PARM(hw_copy, "i");MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)");MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel");/* --------------------------------------------------------------------- */static inline unsigned ld2(unsigned int x){	unsigned exp=16,l=5,r=0;	static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};	/* num: 2, 4, 16, 256, 65536 */	/* exp: 1, 2,  4,   8,    16 */	while(l--) {		if( x >= num[l] ) {			if(num[l]>2) x >>= exp;			r+=exp;		}		exp>>=1;	}	return r;}/* --------------------------------------------------------------------- */static void maskb(unsigned int addr, unsigned int mask, unsigned int value){	outb((inb(addr) & mask) | value, addr);}static void maskw(unsigned int addr, unsigned int mask, unsigned int value){	outw((inw(addr) & mask) | value, addr);}static void maskl(unsigned int addr, unsigned int mask, unsigned int value){	outl((inl(addr) & mask) | value, addr);}static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count){	if (addr)	    outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);}static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count){	outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0);}static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count){	outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);	if (s->status & DO_DUAL_DAC)		set_dmadac1(s, 0, count);}static void set_countadc(struct cm_state *s, unsigned count){	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);}static void set_countdac(struct cm_state *s, unsigned count){	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);	if (s->status & DO_DUAL_DAC)	    set_countadc(s, count);}static unsigned get_dmadac(struct cm_state *s){	unsigned int curr_addr;	curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];	curr_addr = s->dma_dac.dmasize - curr_addr;	return curr_addr;}static unsigned get_dmaadc(struct cm_state *s){	unsigned int curr_addr;	curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];	curr_addr = s->dma_adc.dmasize - curr_addr;	return curr_addr;}static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data){	unsigned char regval, pseudo;	// pseudo register	if (idx == DSP_MIX_AUXVOL_L) {		data >>= 4;		data &= 0x0f;		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);		return;	}	if (idx == DSP_MIX_AUXVOL_R) {		data &= 0xf0;		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);		return;	}	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	// pseudo bits	if (idx == DSP_MIX_OUTMIXIDX) {		pseudo = data & ~0x1f;		pseudo >>= 1;		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);	}	if (idx == DSP_MIX_ADCMIXIDX_L) {		pseudo = data & 0x80;		pseudo >>= 1;		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);	}	if (idx == DSP_MIX_ADCMIXIDX_R) {		pseudo = data & 0x80;		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);	}	outb(data, s->iobase + CODEC_SB16_DATA);	udelay(10);}static unsigned char rdmixer(struct cm_state *s, unsigned char idx){	unsigned char v, pseudo;	// pseudo register	if (idx == DSP_MIX_AUXVOL_L) {		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;		v <<= 4;		return v;	}	if (idx == DSP_MIX_AUXVOL_L) {		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;		return v;	}	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	v = inb(s->iobase + CODEC_SB16_DATA);	udelay(10);	// pseudo bits	if (idx == DSP_MIX_OUTMIXIDX) {		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;		pseudo <<= 1;		v |= pseudo;	}	if (idx == DSP_MIX_ADCMIXIDX_L) {		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;		pseudo <<= 1;		v |= pseudo;	}	if (idx == DSP_MIX_ADCMIXIDX_R) {		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;		v |= pseudo;	}	return v;}static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data){	if (mask && s->chip_version > 0) {	/* 8338 cannot keep this */		s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);		udelay(10);	}	s->fmt = (s->fmt & mask) | data;	outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);	udelay(10);}static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	set_fmt_unlocked(s,mask,data);	spin_unlock_irqrestore(&s->lock, flags);}static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data){	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);	udelay(10);}static struct {	unsigned	rate;	unsigned	lower;	unsigned	upper;	unsigned char	freq;} rate_lookup[] ={	{ 5512,		(0 + 5512) / 2,		(5512 + 8000) / 2,	0 },	{ 8000,		(5512 + 8000) / 2,	(8000 + 11025) / 2,	4 },	{ 11025,	(8000 + 11025) / 2,	(11025 + 16000) / 2,	1 },	{ 16000,	(11025 + 16000) / 2,	(16000 + 22050) / 2,	5 },	{ 22050,	(16000 + 22050) / 2,	(22050 + 32000) / 2,	2 },	{ 32000,	(22050 + 32000) / 2,	(32000 + 44100) / 2,	6 },	{ 44100,	(32000 + 44100) / 2,	(44100 + 48000) / 2,	3 },	{ 48000,	(44100 + 48000) / 2,	48000,			7 }};static void set_spdif_copyright(struct cm_state *s, int spdif_copyright){	/* enable SPDIF-in Copyright */	maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);}static void set_spdif_loop(struct cm_state *s, int spdif_loop){	/* enable SPDIF loop */	if (spdif_loop) {		s->status |= DO_SPDIF_LOOP;		/* turn on spdif-in to spdif-out */		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);	} else {		s->status &= ~DO_SPDIF_LOOP;		/* turn off spdif-in to spdif-out */		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);	}}static void set_spdif_monitor(struct cm_state *s, int channel){	// SPDO2DAC	maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);	// CDPLAY	if (s->chip_version >= 39)		maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);}static void set_spdifout_level(struct cm_state *s, int level5v){	/* SPDO5V */	if (s->chip_version > 0)		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);}static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse){	if (s->chip_version == 0)	/* 8338 has not this feature */		return;	if (spdif_inverse) {		/* turn on spdif-in inverse */		if (s->chip_version >= 39)			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);		else			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);	} else {		/* turn off spdif-ininverse */		if (s->chip_version >= 39)			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);		else			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);	}}static void set_spdifin_channel2(struct cm_state *s, int channel2){	/* SELSPDIFI2 */	if (s->chip_version >= 39)		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);}static void set_spdifin_valid(struct cm_state *s, int valid){	/* SPDVALID */	maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);}static void set_spdifout_unlocked(struct cm_state *s, unsigned rate){	if (rate != 48000 && rate != 44100)		rate = 0;	if (rate == 48000 || rate == 44100) {		set_spdif_loop(s, 0);		// SPDF_1		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);		// SPDIFI48K SPDF_AC97		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);		if (s->chip_version >= 55)		// SPD32KFMT			maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0);		if (s->chip_version > 0)		// ENSPDOUT			maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);		// monitor SPDIF out		set_spdif_monitor(s, 2);		s->status |= DO_SPDIF_OUT;	} else {		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);		// monitor none		set_spdif_monitor(s, 0);		s->status &= ~DO_SPDIF_OUT;	}}static void set_spdifout(struct cm_state *s, unsigned rate){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	set_spdifout_unlocked(s,rate);	spin_unlock_irqrestore(&s->lock, flags);}static void set_spdifin_unlocked(struct cm_state *s, unsigned rate){	if (rate == 48000 || rate == 44100) {		// SPDF_1		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);		// SPDIFI48K SPDF_AC97		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);		s->status |= DO_SPDIF_IN;	} else {		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);		s->status &= ~DO_SPDIF_IN;	}}static void set_spdifin(struct cm_state *s, unsigned rate){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	set_spdifin_unlocked(s,rate);	spin_unlock_irqrestore(&s->lock, flags);}/* find parity for bit 4~30 */static unsigned parity(unsigned data){	unsigned parity = 0;	int counter = 4;	data >>= 4;	// start from bit 4	while (counter <= 30) {		if (data & 1)			parity++;		data >>= 1;		counter++;	}	return parity & 1;}static void set_ac3_unlocked(struct cm_state *s, unsigned rate){	if (!(s->capability & CAN_AC3))		return;	/* enable AC3 */	if (rate && rate != 44100)		rate = 48000;	if (rate == 48000 || rate == 44100) {		// mute DAC		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);		if (s->chip_version >= 39)			maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1);		// AC3EN for 039, 0x04		if (s->chip_version >= 39) {			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);			if (s->chip_version == 55)				maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0);		// AC3EN for 037, 0x10		} else if (s->chip_version == 37)			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);		if (s->capability & CAN_AC3_HW) {			// SPD24SEL for 039, 0x20, but cannot be set			if (s->chip_version == 39)				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);			// SPD24SEL for 037, 0x02			else if (s->chip_version == 37)				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);			if (s->chip_version >= 39)				maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);			s->status |= DO_AC3_HW;		 } else {			// SPD32SEL for 037 & 039			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);			// set 176K sample rate to fix 033 HW bug			if (s->chip_version == 33) {				if (rate == 48000)					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);				else					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);			}			s->status |= DO_AC3_SW;		}	} else {		maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);		if (s->chip_version >= 39)			maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0);		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0);		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);

⌨️ 快捷键说明

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