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

📄 azt3328.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_azf3328_info_mixer, \  .get = snd_azf3328_get_mixer, .put = snd_azf3328_put_mixer, \  .private_value = COMPOSE_MIXER_REG(reg, shift, 0, mask, invert, 0, 0), \}#define AZF3328_MIXER_ENUM(xname, reg, enum_c, shift) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_azf3328_info_mixer_enum, \  .get = snd_azf3328_get_mixer_enum, .put = snd_azf3328_put_mixer_enum, \  .private_value = COMPOSE_MIXER_REG(reg, shift, 0, 0, 0, 0, enum_c), \}static int snd_azf3328_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	azf3328_mixer_reg_t reg;	snd_azf3328_dbgcallenter();	snd_azf3328_mixer_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;	snd_azf3328_dbgcallleave();	return 0;}static int snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	azf3328_t *chip = snd_kcontrol_chip(kcontrol);	azf3328_mixer_reg_t reg;	unsigned int oreg, val;	snd_azf3328_dbgcallenter();	snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);	oreg = inw(chip->mixer_port + reg.reg);	val = (oreg >> reg.lchan_shift) & reg.mask;	if (reg.invert)		val = reg.mask - val;	ucontrol->value.integer.value[0] = val;	if (reg.stereo) {		val = (oreg >> reg.rchan_shift) & reg.mask;		if (reg.invert)			val = reg.mask - val;		ucontrol->value.integer.value[1] = val;	}	snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", reg.reg, oreg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo);	snd_azf3328_dbgcallleave();	return 0;}static int snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	azf3328_t *chip = snd_kcontrol_chip(kcontrol);	azf3328_mixer_reg_t reg;	unsigned int oreg, nreg, val;	snd_azf3328_dbgcallenter();	snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);	oreg = inw(chip->mixer_port + reg.reg);	val = ucontrol->value.integer.value[0] & reg.mask;	if (reg.invert)		val = reg.mask - val;	nreg = oreg & ~(reg.mask << reg.lchan_shift);	nreg |= (val << reg.lchan_shift);	if (reg.stereo) {		val = ucontrol->value.integer.value[1] & reg.mask;		if (reg.invert)			val = reg.mask - val;		nreg &= ~(reg.mask << reg.rchan_shift);		nreg |= (val << reg.rchan_shift);	}	if (reg.mask >= 0x07) /* it's a volume control, so better take care */		snd_azf3328_mixer_write_volume_gradually(chip, reg.reg, nreg >> 8, nreg & 0xff, SET_CHAN_LEFT|SET_CHAN_RIGHT, 0); /* just set both channels, doesn't matter */	else        	outw(nreg, chip->mixer_port + reg.reg);	snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], oreg, reg.lchan_shift, reg.rchan_shift, nreg, inw(chip->mixer_port + reg.reg));	snd_azf3328_dbgcallleave();	return (nreg != oreg);}static int snd_azf3328_info_mixer_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	azf3328_mixer_reg_t reg;	static char *texts1[2] = { "ModemOut1", "ModemOut2" };	static char *texts2[2] = { "MonoSelectSource1", "MonoSelectSource2" };        static char *texts3[8] = {                "Mic", "CD", "Video", "Aux", "Line",                "Mix", "Mix Mono", "Phone"        };	snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;        uinfo->count = (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1;        uinfo->value.enumerated.items = reg.enum_c;        if (uinfo->value.enumerated.item > reg.enum_c - 1U)                uinfo->value.enumerated.item = reg.enum_c - 1U;	if (reg.reg == IDX_MIXER_ADVCTL2)	{		if (reg.lchan_shift == 8) /* modem out sel */			strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]);		else /* mono sel source */			strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]);	}	else        	strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item]);        return 0;}static int snd_azf3328_get_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	azf3328_mixer_reg_t reg;        azf3328_t *chip = snd_kcontrol_chip(kcontrol);        unsigned short val;        	snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);	val = inw(chip->mixer_port + reg.reg);	if (reg.reg == IDX_MIXER_REC_SELECT)	{        	ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1);        	ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1);	}	else        	ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1);	snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1], reg.lchan_shift, reg.enum_c);        return 0;}static int snd_azf3328_put_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	azf3328_mixer_reg_t reg;        azf3328_t *chip = snd_kcontrol_chip(kcontrol);	unsigned int oreg, nreg, val;        	snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);	oreg = inw(chip->mixer_port + reg.reg);	val = oreg;	if (reg.reg == IDX_MIXER_REC_SELECT)	{        	if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U ||            	ucontrol->value.enumerated.item[1] > reg.enum_c - 1U)                	return -EINVAL;        	val = (ucontrol->value.enumerated.item[0] << 8) |        	      (ucontrol->value.enumerated.item[1] << 0);	}	else	{        	if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U)                	return -EINVAL;		val &= ~((reg.enum_c - 1) << reg.lchan_shift);        	val |= (ucontrol->value.enumerated.item[0] << reg.lchan_shift);	}	outw(val, chip->mixer_port + reg.reg);	nreg = val;	snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg);	return (nreg != oreg);}static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = {	AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1),	AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1),	AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1),	AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1),	AZF3328_MIXER_SWITCH("Wave Playback 3D Bypass", IDX_MIXER_ADVCTL2, 7, 1),	AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1),	AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1),	AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1),	AZF3328_MIXER_VOL_STEREO("CD Playback Volume", IDX_MIXER_CDAUDIO, 0x1f, 1),	AZF3328_MIXER_SWITCH("Capture Switch", IDX_MIXER_REC_VOLUME, 15, 1),	AZF3328_MIXER_VOL_STEREO("Capture Volume", IDX_MIXER_REC_VOLUME, 0x0f, 0),	AZF3328_MIXER_ENUM("Capture Source", IDX_MIXER_REC_SELECT, 8, 0),	AZF3328_MIXER_SWITCH("Mic Playback Switch", IDX_MIXER_MIC, 15, 1),	AZF3328_MIXER_VOL_MONO("Mic Playback Volume", IDX_MIXER_MIC, 0x1f, 1),	AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0),	AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1),	AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1),	AZF3328_MIXER_SWITCH("PCBeep Playback Switch", IDX_MIXER_PCBEEP, 15, 1),	AZF3328_MIXER_VOL_SPECIAL("PCBeep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1),	AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1),	AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1),	AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1),	AZF3328_MIXER_VOL_STEREO("Aux Playback Volume", IDX_MIXER_AUX, 0x1f, 1),	AZF3328_MIXER_SWITCH("Modem Playback Switch", IDX_MIXER_MODEMOUT, 15, 1),	AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1),	AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1),	AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1),	AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8),	AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9),	AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0),	AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0),	AZF3328_MIXER_SWITCH("3D Control - Toggle", IDX_MIXER_ADVCTL2, 13, 0),	AZF3328_MIXER_VOL_SPECIAL("3D Control - Volume", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */	AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */#if MIXER_TESTING	AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0),	AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0),	AZF3328_MIXER_SWITCH("2", IDX_MIXER_ADVCTL2, 2, 0),	AZF3328_MIXER_SWITCH("3", IDX_MIXER_ADVCTL2, 3, 0),	AZF3328_MIXER_SWITCH("4", IDX_MIXER_ADVCTL2, 4, 0),	AZF3328_MIXER_SWITCH("5", IDX_MIXER_ADVCTL2, 5, 0),	AZF3328_MIXER_SWITCH("6", IDX_MIXER_ADVCTL2, 6, 0),	AZF3328_MIXER_SWITCH("7", IDX_MIXER_ADVCTL2, 7, 0),	AZF3328_MIXER_SWITCH("8", IDX_MIXER_ADVCTL2, 8, 0),	AZF3328_MIXER_SWITCH("9", IDX_MIXER_ADVCTL2, 9, 0),	AZF3328_MIXER_SWITCH("10", IDX_MIXER_ADVCTL2, 10, 0),	AZF3328_MIXER_SWITCH("11", IDX_MIXER_ADVCTL2, 11, 0),	AZF3328_MIXER_SWITCH("12", IDX_MIXER_ADVCTL2, 12, 0),	AZF3328_MIXER_SWITCH("13", IDX_MIXER_ADVCTL2, 13, 0),	AZF3328_MIXER_SWITCH("14", IDX_MIXER_ADVCTL2, 14, 0),	AZF3328_MIXER_SWITCH("15", IDX_MIXER_ADVCTL2, 15, 0),#endif};#define AZF3328_INIT_VALUES (sizeof(snd_azf3328_init_values)/sizeof(unsigned int)/2)static unsigned int snd_azf3328_init_values[][2] = {        { IDX_MIXER_PLAY_MASTER,	MIXER_MUTE_MASK|0x1f1f },        { IDX_MIXER_MODEMOUT,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_BASSTREBLE,		0x0000 },	{ IDX_MIXER_PCBEEP,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_MODEMIN,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_MIC,		MIXER_MUTE_MASK|0x001f },	{ IDX_MIXER_LINEIN,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_CDAUDIO,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_VIDEO,		MIXER_MUTE_MASK|0x1f1f },	{ IDX_MIXER_AUX,		MIXER_MUTE_MASK|0x1f1f },        { IDX_MIXER_WAVEOUT,		MIXER_MUTE_MASK|0x1f1f },        { IDX_MIXER_FMSYNTH,		MIXER_MUTE_MASK|0x1f1f },        { IDX_MIXER_REC_VOLUME,		MIXER_MUTE_MASK|0x0707 },};static int __devinit snd_azf3328_mixer_new(azf3328_t *chip){	snd_card_t *card;	snd_kcontrol_new_t *sw;	unsigned int idx;	int err;	snd_azf3328_dbgcallenter();	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);	card = chip->card;	/* mixer reset */	snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE);	/* mute and zero volume channels */	for (idx = 0; idx < AZF3328_INIT_VALUES; idx++) {		snd_azf3328_mixer_write(chip, snd_azf3328_init_values[idx][0], snd_azf3328_init_values[idx][1], WORD_VALUE);	}		/* add mixer controls */	sw = snd_azf3328_mixer_controls;	for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); idx++, sw++) {		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0)			return err;	}	snd_component_add(card, "AZF3328 mixer");	strcpy(card->mixername, "AZF3328 mixer");	snd_azf3328_dbgcallleave();	return 0;}static int snd_azf3328_hw_params(snd_pcm_substream_t * substream,				 snd_pcm_hw_params_t * hw_params){	int res;	snd_azf3328_dbgcallenter();	res = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));	snd_azf3328_dbgcallleave();	return res;}static int snd_azf3328_hw_free(snd_pcm_substream_t * substream){	snd_azf3328_dbgcallenter();	snd_pcm_lib_free_pages(substream);	snd_azf3328_dbgcallleave();	return 0;}static void snd_azf3328_setfmt(azf3328_t *chip,			       unsigned int reg,			       unsigned int bitrate,			       unsigned int format_width,			       unsigned int channels){	unsigned int val = 0xff00;	unsigned long flags;	snd_azf3328_dbgcallenter();	switch (bitrate) {	case  5512: val |= 0x0d; break; /* the AZF3328 names it "5510" for some strange reason */	case  6620: val |= 0x0b; break;	case  8000: val |= 0x00; break;	case  9600: val |= 0x08; break;	case 11025: val |= 0x01; break;	case 16000: val |= 0x02; break;	case 22050: val |= 0x03; break;	case 32000: val |= 0x04; break;	case 44100: val |= 0x05; break;	case 48000: val |= 0x06; break;	case 64000: val |= 0x07; break;	default:		snd_printk("unknown bitrate %d, assuming 44.1kHz!\n", bitrate);		val |= 0x05; /* 44100 */		break;	}	/* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) */	/* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) */	/* val = 0xff0a; 47m30.599s (4764,891Hz; -> 4800Hz???) */	/* val = 0xff0c; 57m0.510s (4010,263Hz; -> 4000Hz???) */	/* val = 0xff05; 5m11.556s (... -> 44100Hz) */	/* val = 0xff03; 10m21.529s (21872,463Hz; -> 22050Hz???) */	/* val = 0xff0f; 20m41.883s (10937,993Hz; -> 11025Hz???) */	/* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */	/* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */	if (channels == 2)		val |= SOUNDFORMAT_FLAG_2CHANNELS;	if (format_width == 16)		val |= SOUNDFORMAT_FLAG_16BIT;	spin_lock_irqsave(&chip->reg_lock, flags);		/* set bitrate/format */	outw(val, chip->codec_port+reg);		/* changing the bitrate/format settings switches off the	 * audio output with an annoying click in case of 8/16bit format change	 * (maybe shutting down DAC/ADC?), thus immediately	 * do some tweaking to reenable it and get rid of the clicking	 * (FIXME: yes, it works, but what exactly am I doing here?? :)	 * FIXME: does this have some side effects for full-duplex	 * or other dramatic side effects? */	if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */		outw(inw(chip->codec_port + IDX_IO_PLAY_FLAGS)|DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_PLAY_FLAGS);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_azf3328_dbgcallleave();}static void snd_azf3328_setdmaa(azf3328_t *chip,				long unsigned int addr,                                unsigned int count,                                unsigned int size,				int do_recording){	long unsigned int addr1;	long unsigned int addr2;	unsigned int count1;	unsigned int count2;	unsigned long flags;	int reg_offs = do_recording ? 0x20 : 0x00;	snd_azf3328_dbgcallenter();	/* AZF3328 uses a two buffer pointer DMA playback approach */	if (!chip->is_playing)	{		addr1 = addr;		addr2 = addr+(size/2);		count1 = (size/2)-1;		count2 = (size/2)-1;#if DEBUG_PLAY_REC		snd_azf3328_dbgplay("setting dma: buf1 %08lx[%d], buf2 %08lx[%d]\n", addr1, count1, addr2, count2);#endif		spin_lock_irqsave(&chip->reg_lock, flags);		outl(addr1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_1);		outl(addr2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_2);		outw(count1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_1);		outw(count2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_2);		spin_unlock_irqrestore(&chip->reg_lock, flags);	}	snd_azf3328_dbgcallleave();}

⌨️ 快捷键说明

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