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

📄 fm801.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		udelay(1);		val <<= 1;		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA))			val |= 1;	}	spin_unlock_irq(&chip->reg_lock);	return val;}/* 256PCPR GPIO numbers */#define TEA_256PCPR_BUS_CLOCK		0#define TEA_256PCPR_DATA		1#define TEA_256PCPR_WRITE_ENABLE	2	/* inverted */static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val){	struct fm801 *chip = tea->private_data;	unsigned short reg;	int i = 25;	spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines and set write enable bit */	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK);	/* all of lines are in the write direction */	/* clear data and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) |	         FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_256PCPR_DATA) |	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) |		 FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE));	outw(reg, FM801_REG(chip, GPIO_CTRL));	udelay(1);	while (i--) {		if (val & (1 << i))			reg |= FM801_GPIO_GP(TEA_256PCPR_DATA);		else			reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);	}	/* and reset the write enable bit */	reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) |	       FM801_GPIO_GP(TEA_256PCPR_DATA);	outw(reg, FM801_REG(chip, GPIO_CTRL));	spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea){	struct fm801 *chip = tea->private_data;	unsigned short reg;	unsigned int val = 0;	int i;		spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines, set data direction to input */	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) |	       FM801_GPIO_GD(TEA_256PCPR_DATA) |	       FM801_GPIO_GP(TEA_256PCPR_DATA) |	       FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE);	/* all of lines are in the write direction, except data */	/* clear data, write enable and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK));	for (i = 0; i < 24; i++) {		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		val <<= 1;		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA))			val |= 1;	}	spin_unlock_irq(&chip->reg_lock);	return val;}/* 64PCR GPIO numbers */#define TEA_64PCR_BUS_CLOCK		0#define TEA_64PCR_WRITE_ENABLE		1	/* inverted */#define TEA_64PCR_DATA			2static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val){	struct fm801 *chip = tea->private_data;	unsigned short reg;	int i = 25;	spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines and set write enable bit */	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK);	/* all of lines are in the write direction */	/* clear data and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) |	         FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_64PCR_DATA) |	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) |		 FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE));	outw(reg, FM801_REG(chip, GPIO_CTRL));	udelay(1);	while (i--) {		if (val & (1 << i))			reg |= FM801_GPIO_GP(TEA_64PCR_DATA);		else			reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);	}	/* and reset the write enable bit */	reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) |	       FM801_GPIO_GP(TEA_64PCR_DATA);	outw(reg, FM801_REG(chip, GPIO_CTRL));	spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea){	struct fm801 *chip = tea->private_data;	unsigned short reg;	unsigned int val = 0;	int i;		spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines, set data direction to input */	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) |	       FM801_GPIO_GD(TEA_64PCR_DATA) |	       FM801_GPIO_GP(TEA_64PCR_DATA) |	       FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);	/* all of lines are in the write direction, except data */	/* clear data, write enable and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK));	for (i = 0; i < 24; i++) {		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		val <<= 1;		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA))			val |= 1;	}	spin_unlock_irq(&chip->reg_lock);	return val;}static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {	{		/* 1 = MediaForte 256-PCS */		.write = snd_fm801_tea575x_256pcs_write,		.read = snd_fm801_tea575x_256pcs_read,	},	{		/* 2 = MediaForte 256-PCPR */		.write = snd_fm801_tea575x_256pcpr_write,		.read = snd_fm801_tea575x_256pcpr_read,	},	{		/* 3 = MediaForte 64-PCR */		.write = snd_fm801_tea575x_64pcr_write,		.read = snd_fm801_tea575x_64pcr_read,	}};#endif/* *  Mixer routines */#define FM801_SINGLE(xname, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_single, \  .get = snd_fm801_get_single, .put = snd_fm801_put_single, \  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_fm801_info_single(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_fm801_get_single(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift) & mask;	if (invert)		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];	return 0;}static int snd_fm801_put_single(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	unsigned short val;	val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	return snd_fm801_update_bits(chip, reg, mask << shift, val << shift);}#define FM801_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \  .get = snd_fm801_get_double, .put = snd_fm801_put_double, \  .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) }#define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \  .name = xname, .info = snd_fm801_info_double, \  .get = snd_fm801_get_double, .put = snd_fm801_put_double, \  .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \  .tlv = { .p = (xtlv) } }static int snd_fm801_info_double(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_fm801_get_double(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);        int reg = kcontrol->private_value & 0xff;	int shift_left = (kcontrol->private_value >> 8) & 0x0f;	int shift_right = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	spin_lock_irq(&chip->reg_lock);	ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift_left) & mask;	ucontrol->value.integer.value[1] = (inw(chip->port + reg) >> shift_right) & mask;	spin_unlock_irq(&chip->reg_lock);	if (invert) {		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];	}	return 0;}static int snd_fm801_put_double(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift_left = (kcontrol->private_value >> 8) & 0x0f;	int shift_right = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	unsigned short val1, val2; 	val1 = ucontrol->value.integer.value[0] & mask;	val2 = ucontrol->value.integer.value[1] & mask;	if (invert) {		val1 = mask - val1;		val2 = mask - val2;	}	return snd_fm801_update_bits(chip, reg,				     (mask << shift_left) | (mask << shift_right),				     (val1 << shift_left ) | (val2 << shift_right));}static int snd_fm801_info_mux(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_info *uinfo){	static char *texts[5] = {		"AC97 Primary", "FM", "I2S", "PCM", "AC97 Secondary"	}; 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 5;	if (uinfo->value.enumerated.item > 4)		uinfo->value.enumerated.item = 4;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol,			     struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);        unsigned short val; 	val = inw(FM801_REG(chip, REC_SRC)) & 7;	if (val > 4)		val = 4;        ucontrol->value.enumerated.item[0] = val;        return 0;}static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol,			     struct snd_ctl_elem_value *ucontrol){	struct fm801 *chip = snd_kcontrol_chip(kcontrol);        unsigned short val;         if ((val = ucontrol->value.enumerated.item[0]) > 4)                return -EINVAL;	return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);}static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);#define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = {FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1,		 db_scale_dsp),FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1),FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1,		 db_scale_dsp),FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1),FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1,		 db_scale_dsp),FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Digital Capture Source",	.info = snd_fm801_info_mux,	.get = snd_fm801_get_mux,	.put = snd_fm801_put_mux,}};#define FM801_CONTROLS_MULTI ARRAY_SIZE(snd_fm801_controls_multi)static struct snd_kcontrol_new snd_fm801_controls_multi[] __devinitdata = {FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0),FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0),FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0),FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",PLAYBACK,SWITCH), FM801_I2S_MODE, 9, 1, 0),FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",CAPTURE,SWITCH), FM801_I2S_MODE, 10, 1, 0),FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), FM801_GEN_CTRL, 2, 1, 0),

⌨️ 快捷键说明

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