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

📄 cmipci.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
static int __devinit snd_cmipci_pcm_spdif_new(cmipci_t *cm, int device){	snd_pcm_t *pcm;	int err;	err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_spdif_ops);	pcm->private_data = cm;	pcm->private_free = snd_cmipci_pcm_free;	pcm->info_flags = 0;	strcpy(pcm->name, "C-Media PCI IEC958");	cm->pcm_spdif = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);	return 0;}/* * mixer interface: * - CM8338/8738 has a compatible mixer interface with SB16, but *   lack of some elements like tone control, i/o gain and AGC. * - Access to native registers: *   - A 3D switch *   - Output mute switches */static void snd_cmipci_mixer_write(cmipci_t *s, unsigned char idx, unsigned char data){	outb(idx, s->iobase + CM_REG_SB16_ADDR);	outb(data, s->iobase + CM_REG_SB16_DATA);}static unsigned char snd_cmipci_mixer_read(cmipci_t *s, unsigned char idx){	unsigned char v;	outb(idx, s->iobase + CM_REG_SB16_ADDR);	v = inb(s->iobase + CM_REG_SB16_DATA);	return v;}/* * general mixer element */typedef struct cmipci_sb_reg {	unsigned int left_reg, right_reg;	unsigned int left_shift, right_shift;	unsigned int mask;	unsigned int invert: 1;	unsigned int stereo: 1;} cmipci_sb_reg_t;#define COMPOSE_SB_REG(lreg,rreg,lshift,rshift,mask,invert,stereo) \ ((lreg) | ((rreg) << 8) | (lshift << 16) | (rshift << 19) | (mask << 24) | (invert << 22) | (stereo << 23))#define CMIPCI_DOUBLE(xname, left_reg, right_reg, left_shift, right_shift, mask, invert, stereo) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_volume, \  .get = snd_cmipci_get_volume, .put = snd_cmipci_put_volume, \  .private_value = COMPOSE_SB_REG(left_reg, right_reg, left_shift, right_shift, mask, invert, stereo), \}#define CMIPCI_SB_VOL_STEREO(xname,reg,shift,mask) CMIPCI_DOUBLE(xname, reg, reg+1, shift, shift, mask, 0, 1)#define CMIPCI_SB_VOL_MONO(xname,reg,shift,mask) CMIPCI_DOUBLE(xname, reg, reg, shift, shift, mask, 0, 0)#define CMIPCI_SB_SW_STEREO(xname,lshift,rshift) CMIPCI_DOUBLE(xname, SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, lshift, rshift, 1, 0, 1)#define CMIPCI_SB_SW_MONO(xname,shift) CMIPCI_DOUBLE(xname, SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, shift, shift, 1, 0, 0)static void cmipci_sb_reg_decode(cmipci_sb_reg_t *r, unsigned long val){	r->left_reg = val & 0xff;	r->right_reg = (val >> 8) & 0xff;	r->left_shift = (val >> 16) & 0x07;	r->right_shift = (val >> 19) & 0x07;	r->invert = (val >> 22) & 1;	r->stereo = (val >> 23) & 1;	r->mask = (val >> 24) & 0xff;}static int snd_cmipci_info_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo){	cmipci_sb_reg_t reg;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = reg.stereo + 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = reg.mask;	return 0;} static int snd_cmipci_get_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	int val;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	val = (snd_cmipci_mixer_read(cm, reg.left_reg) >> reg.left_shift) & reg.mask;	if (reg.invert)		val = reg.mask - val;	ucontrol->value.integer.value[0] = val;	if (reg.stereo) {		val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask;		if (reg.invert)			val = reg.mask - val;		 ucontrol->value.integer.value[1] = val;	}	spin_unlock_irq(&cm->reg_lock);	return 0;}static int snd_cmipci_put_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	int change;	int left, right, oleft, oright;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	left = ucontrol->value.integer.value[0] & reg.mask;	if (reg.invert)		left = reg.mask - left;	left <<= reg.left_shift;	if (reg.stereo) {		right = ucontrol->value.integer.value[1] & reg.mask;		if (reg.invert)			right = reg.mask - right;		right <<= reg.right_shift;	} else		right = 0;	spin_lock_irq(&cm->reg_lock);	oleft = snd_cmipci_mixer_read(cm, reg.left_reg);	left |= oleft & ~(reg.mask << reg.left_shift);	change = left != oleft;	if (reg.stereo) {		if (reg.left_reg != reg.right_reg) {			snd_cmipci_mixer_write(cm, reg.left_reg, left);			oright = snd_cmipci_mixer_read(cm, reg.right_reg);		} else			oright = left;		right |= oright & ~(reg.mask << reg.right_shift);		change |= right != oright;		snd_cmipci_mixer_write(cm, reg.right_reg, right);	} else		snd_cmipci_mixer_write(cm, reg.left_reg, left);	spin_unlock_irq(&cm->reg_lock);	return change;}/* * input route (left,right) -> (left,right) */#define CMIPCI_SB_INPUT_SW(xname, left_shift, right_shift) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_input_sw, \  .get = snd_cmipci_get_input_sw, .put = snd_cmipci_put_input_sw, \  .private_value = COMPOSE_SB_REG(SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, left_shift, right_shift, 1, 0, 1), \}static int snd_cmipci_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 4;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;} static int snd_cmipci_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	int val1, val2;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	val1 = snd_cmipci_mixer_read(cm, reg.left_reg);	val2 = snd_cmipci_mixer_read(cm, reg.right_reg);	spin_unlock_irq(&cm->reg_lock);	ucontrol->value.integer.value[0] = (val1 >> reg.left_shift) & 1;	ucontrol->value.integer.value[1] = (val2 >> reg.left_shift) & 1;	ucontrol->value.integer.value[2] = (val1 >> reg.right_shift) & 1;	ucontrol->value.integer.value[3] = (val2 >> reg.right_shift) & 1;	return 0;}static int snd_cmipci_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	int change;	int val1, val2, oval1, oval2;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	oval1 = snd_cmipci_mixer_read(cm, reg.left_reg);	oval2 = snd_cmipci_mixer_read(cm, reg.right_reg);	val1 = oval1 & ~((1 << reg.left_shift) | (1 << reg.right_shift));	val2 = oval2 & ~((1 << reg.left_shift) | (1 << reg.right_shift));	val1 |= (ucontrol->value.integer.value[0] & 1) << reg.left_shift;	val2 |= (ucontrol->value.integer.value[1] & 1) << reg.left_shift;	val1 |= (ucontrol->value.integer.value[2] & 1) << reg.right_shift;	val2 |= (ucontrol->value.integer.value[3] & 1) << reg.right_shift;	change = val1 != oval1 || val2 != oval2;	snd_cmipci_mixer_write(cm, reg.left_reg, val1);	snd_cmipci_mixer_write(cm, reg.right_reg, val2);	spin_unlock_irq(&cm->reg_lock);	return change;}/* * native mixer switches/volumes */#define CMIPCI_MIXER_SW_STEREO(xname, reg, lshift, rshift, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_native_mixer, \  .get = snd_cmipci_get_native_mixer, .put = snd_cmipci_put_native_mixer, \  .private_value = COMPOSE_SB_REG(reg, reg, lshift, rshift, 1, invert, 1), \}#define CMIPCI_MIXER_SW_MONO(xname, reg, shift, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_native_mixer, \  .get = snd_cmipci_get_native_mixer, .put = snd_cmipci_put_native_mixer, \  .private_value = COMPOSE_SB_REG(reg, reg, shift, shift, 1, invert, 0), \}#define CMIPCI_MIXER_VOL_STEREO(xname, reg, lshift, rshift, mask) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_native_mixer, \  .get = snd_cmipci_get_native_mixer, .put = snd_cmipci_put_native_mixer, \  .private_value = COMPOSE_SB_REG(reg, reg, lshift, rshift, mask, 0, 1), \}#define CMIPCI_MIXER_VOL_MONO(xname, reg, shift, mask) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_native_mixer, \  .get = snd_cmipci_get_native_mixer, .put = snd_cmipci_put_native_mixer, \  .private_value = COMPOSE_SB_REG(reg, reg, shift, shift, mask, 0, 0), \}static int snd_cmipci_info_native_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	cmipci_sb_reg_t reg;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = reg.stereo + 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = reg.mask;	return 0;}static int snd_cmipci_get_native_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	unsigned char oreg, val;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	oreg = inb(cm->iobase + reg.left_reg);	val = (oreg >> reg.left_shift) & reg.mask;	if (reg.invert)		val = reg.mask - val;	ucontrol->value.integer.value[0] = val;	if (reg.stereo) {		val = (oreg >> reg.right_shift) & reg.mask;		if (reg.invert)			val = reg.mask - val;		ucontrol->value.integer.value[1] = val;	}	spin_unlock_irq(&cm->reg_lock);	return 0;}static int snd_cmipci_put_native_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	cmipci_sb_reg_t reg;	unsigned char oreg, nreg, val;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	oreg = inb(cm->iobase + reg.left_reg);	val = ucontrol->value.integer.value[0] & reg.mask;	if (reg.invert)		val = reg.mask - val;	nreg = oreg & ~(reg.mask << reg.left_shift);	nreg |= (val << reg.left_shift);	if (reg.stereo) {		val = ucontrol->value.integer.value[1] & reg.mask;		if (reg.invert)			val = reg.mask - val;		nreg &= ~(reg.mask << reg.right_shift);		nreg |= (val << reg.right_shift);	}	outb(nreg, cm->iobase + reg.left_reg);	spin_unlock_irq(&cm->reg_lock);	return (nreg != oreg);}/* * special case - check mixer sensitivity */static int snd_cmipci_get_native_mixer_sensitive(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	//cmipci_t *cm = snd_kcontrol_chip(kcontrol);	return snd_cmipci_get_native_mixer(kcontrol, ucontrol);}static int snd_cmipci_put_native_mixer_sensitive(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	if (cm->mixer_insensitive) {		/* ignored */		return 0;	}	return snd_cmipci_put_native_mixer(kcontrol, ucontrol);}static snd_kcontrol_new_t snd_cmipci_mixers[] __devinitdata = {	CMIPCI_SB_VOL_STEREO("Master Playback Volume", SB_DSP4_MASTER_DEV, 3, 31),	CMIPCI_MIXER_SW_MONO("3D Control - Switch", CM_REG_MIXER1, CM_X3DEN_SHIFT, 0),	CMIPCI_SB_VOL_STEREO("PCM Playback Volume", SB_DSP4_PCM_DEV, 3, 31),	//CMIPCI_MIXER_SW_MONO("PCM Playback Switch", CM_REG_MIXER1, CM_WSMUTE_SHIFT, 1),	{ /* switch with sensitivity */		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "PCM Playback Switch",		.info = snd_cmipci_info_native_mixer,		.get = snd_cmipci_get_native_mixer_sensitive,		.put = snd_cmipci_put_native_mixer_sensitive,		.private_value = COMPOSE_SB_REG(CM_REG_MIXER1, CM_REG_MIXER1, CM_WSMUTE_SHIFT, CM_WSMUTE_SHIFT, 1, 1, 0),	},	CMIPCI_MIXER_SW_STEREO("PCM Capture Switch", CM_REG_MIXER1, CM_WAVEINL_SHIFT, CM_WAVEINR_SHIFT, 0),	CMIPCI_SB_VOL_STEREO("Synth Playback Volume", SB_DSP4_SYNTH_DEV, 3, 31),	CMIPCI_MIXER_SW_MONO("Synth Playback Switch", CM_REG_MIXER1, CM_FMMUTE_SHIFT, 1),	CMIPCI_SB_INPUT_SW("Synth Capture Route", 6, 5),	CMIPCI_SB_VOL_STEREO("CD Playback Volume", SB_DSP4_CD_DEV, 3, 31),	CMIPCI_SB_SW_STEREO("CD Playback Switch", 2, 1),	CMIPCI_SB_INPUT_SW("CD Capture Route", 2, 1),	CMIPCI_SB_VOL_STEREO("Line Playback Volume", SB_DSP4_LINE_DEV, 3, 31),	CMIPCI_SB_SW_STEREO("Line Playback Switch", 4, 3),	CMIPCI_SB_INPUT_SW("Line Capture Route", 4, 3),	CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),	CMIPCI_SB_SW_MONO("Mic Playback Switch", 0),	CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0),	CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),	CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),	CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),	CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),	CMIPCI_MIXER_SW_MONO("Mic Boost", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),	CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),};/* * other switches */typedef struct snd_cmipci_switch_args {	int reg;		/* register index */	unsigned int mask;	/* mask bits */	unsigned int mask_on;	/* mask bits to turn on */	int is_byte: 1;		/* byte access? */	int ac3_sensitive: 1;	/* access forbidden during non-audio operation? */} snd_cmipci_switch_args_t;static int snd_cmipci_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int _snd_cmipci_uswitch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol, snd_cmipci_switch_args_t *args){	unsigned int val;	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	spin_lock_irq(&cm->reg_lock);	if (args->ac3_sensitive && cm->mixer_insensitive) {		ucontrol->value.integer.value[0] = 0;		spin_unlock_irq(&cm->reg_lock);		return 0;	}	if (args->is_byte)		val = inb(cm->iobase + args->reg);	else		val = snd_cmipci_read(cm, args->reg);	ucontrol->value.integer.value[0] = ((val & args->mask) == args->mask_on) ? 1 : 0;	spin_unlock_irq(&cm->reg_lock);	return 0;}static int snd_cmipci_uswitch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	snd_cmipci_switch_args_t *args = (snd_cmipci_switch_args_t*)kcontrol->private_value;	snd_assert(args != NULL, return -EINVAL);	return _snd_cmipci_uswitch_get(kcontrol, ucontrol, args);}static int _snd_cmipci_uswitch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol, snd_cmipci_switch_args_t *args){	unsigned int val;	int change;	cmipci_t *cm = snd_kcontrol_chip(kcontrol);	spin_lock_irq(&cm->reg_lock);	if (args->ac3_sensitive && cm->mixer_insensitive) {		/* ignored */		spin_unlock_irq(&cm->reg_lock);		return 0;	}	if (args->is_byte)		val = inb(cm->iobase + args->reg);	else		val = snd_cmipci_read(cm, args->reg);	change = (val & args->mask) != (ucontrol->value.integer.value[0] ? args->mask : 0);	if (ch

⌨️ 快捷键说明

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