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

📄 cmipci.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (rec->ch) {		val &= ~CM_CH1FMT_MASK;		val |= rec->fmt << CM_CH1FMT_SHIFT;	} else {		val &= ~CM_CH0FMT_MASK;		val |= rec->fmt << CM_CH0FMT_SHIFT;	}	if (cm->chip_version == 68) {		if (runtime->rate == 88200)			val |= CM_CH0_SRATE_88K << (rec->ch * 2);		else			val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2));		if (runtime->rate == 96000)			val |= CM_CH0_SRATE_96K << (rec->ch * 2);		else			val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2));	}	snd_cmipci_write(cm, CM_REG_CHFORMAT, val);	//snd_printd("cmipci: chformat = %08x\n", val);	rec->running = 0;	spin_unlock_irq(&cm->reg_lock);	return 0;}/* * PCM trigger/stop */static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec,				  int cmd){	unsigned int inthld, chen, reset, pause;	int result = 0;	inthld = CM_CH0_INT_EN << rec->ch;	chen = CM_CHEN0 << rec->ch;	reset = CM_RST_CH0 << rec->ch;	pause = CM_PAUSE0 << rec->ch;	spin_lock(&cm->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		rec->running = 1;		/* set interrupt */		snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, inthld);		cm->ctrl |= chen;		/* enable channel */		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);		//snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);		break;	case SNDRV_PCM_TRIGGER_STOP:		rec->running = 0;		/* disable interrupt */		snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, inthld);		/* reset */		cm->ctrl &= ~chen;		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset);		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset);		rec->needs_silencing = rec->is_dac;		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:	case SNDRV_PCM_TRIGGER_SUSPEND:		cm->ctrl |= pause;		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:	case SNDRV_PCM_TRIGGER_RESUME:		cm->ctrl &= ~pause;		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);		break;	default:		result = -EINVAL;		break;	}	spin_unlock(&cm->reg_lock);	return result;}/* * return the current pointer */static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci_pcm *rec,						struct snd_pcm_substream *substream){	size_t ptr;	unsigned int reg;	if (!rec->running)		return 0;#if 1 // this seems better..	reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2;	ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1);	ptr >>= rec->shift;#else	reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1;	ptr = snd_cmipci_read(cm, reg) - rec->offset;	ptr = bytes_to_frames(substream->runtime, ptr);#endif	if (substream->runtime->channels > 2)		ptr = (ptr * 2) / substream->runtime->channels;	return ptr;}/* * playback */static int snd_cmipci_playback_trigger(struct snd_pcm_substream *substream,				       int cmd){	struct cmipci *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], cmd);}static snd_pcm_uframes_t snd_cmipci_playback_pointer(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_pointer(cm, &cm->channel[CM_CH_PLAY], substream);}/* * capture */static int snd_cmipci_capture_trigger(struct snd_pcm_substream *substream,				     int cmd){	struct cmipci *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], cmd);}static snd_pcm_uframes_t snd_cmipci_capture_pointer(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_pointer(cm, &cm->channel[CM_CH_CAPT], substream);}/* * hw preparation for spdif */static int snd_cmipci_spdif_default_info(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_default_get(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_value *ucontrol){	struct cmipci *chip = snd_kcontrol_chip(kcontrol);	int i;	spin_lock_irq(&chip->reg_lock);	for (i = 0; i < 4; i++)		ucontrol->value.iec958.status[i] = (chip->dig_status >> (i * 8)) & 0xff;	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct cmipci *chip = snd_kcontrol_chip(kcontrol);	int i, change;	unsigned int val;	val = 0;	spin_lock_irq(&chip->reg_lock);	for (i = 0; i < 4; i++)		val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);	change = val != chip->dig_status;	chip->dig_status = val;	spin_unlock_irq(&chip->reg_lock);	return change;}static struct snd_kcontrol_new snd_cmipci_spdif_default __devinitdata ={	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),	.info =		snd_cmipci_spdif_default_info,	.get =		snd_cmipci_spdif_default_get,	.put =		snd_cmipci_spdif_default_put};static int snd_cmipci_spdif_mask_info(struct snd_kcontrol *kcontrol,				      struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_mask_get(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	ucontrol->value.iec958.status[0] = 0xff;	ucontrol->value.iec958.status[1] = 0xff;	ucontrol->value.iec958.status[2] = 0xff;	ucontrol->value.iec958.status[3] = 0xff;	return 0;}static struct snd_kcontrol_new snd_cmipci_spdif_mask __devinitdata ={	.access =	SNDRV_CTL_ELEM_ACCESS_READ,	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),	.info =		snd_cmipci_spdif_mask_info,	.get =		snd_cmipci_spdif_mask_get,};static int snd_cmipci_spdif_stream_info(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_stream_get(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct cmipci *chip = snd_kcontrol_chip(kcontrol);	int i;	spin_lock_irq(&chip->reg_lock);	for (i = 0; i < 4; i++)		ucontrol->value.iec958.status[i] = (chip->dig_pcm_status >> (i * 8)) & 0xff;	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct cmipci *chip = snd_kcontrol_chip(kcontrol);	int i, change;	unsigned int val;	val = 0;	spin_lock_irq(&chip->reg_lock);	for (i = 0; i < 4; i++)		val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);	change = val != chip->dig_pcm_status;	chip->dig_pcm_status = val;	spin_unlock_irq(&chip->reg_lock);	return change;}static struct snd_kcontrol_new snd_cmipci_spdif_stream __devinitdata ={	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),	.info =		snd_cmipci_spdif_stream_info,	.get =		snd_cmipci_spdif_stream_get,	.put =		snd_cmipci_spdif_stream_put};/* *//* save mixer setting and mute for AC3 playback */static int save_mixer_state(struct cmipci *cm){	if (! cm->mixer_insensitive) {		struct snd_ctl_elem_value *val;		unsigned int i;		val = kmalloc(sizeof(*val), GFP_ATOMIC);		if (!val)			return -ENOMEM;		for (i = 0; i < CM_SAVED_MIXERS; i++) {			struct snd_kcontrol *ctl = cm->mixer_res_ctl[i];			if (ctl) {				int event;				memset(val, 0, sizeof(*val));				ctl->get(ctl, val);				cm->mixer_res_status[i] = val->value.integer.value[0];				val->value.integer.value[0] = cm_saved_mixer[i].toggle_on;				event = SNDRV_CTL_EVENT_MASK_INFO;				if (cm->mixer_res_status[i] != val->value.integer.value[0]) {					ctl->put(ctl, val); /* toggle */					event |= SNDRV_CTL_EVENT_MASK_VALUE;				}				ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;				snd_ctl_notify(cm->card, event, &ctl->id);			}		}		kfree(val);		cm->mixer_insensitive = 1;	}	return 0;}/* restore the previously saved mixer status */static void restore_mixer_state(struct cmipci *cm){	if (cm->mixer_insensitive) {		struct snd_ctl_elem_value *val;		unsigned int i;		val = kmalloc(sizeof(*val), GFP_KERNEL);		if (!val)			return;		cm->mixer_insensitive = 0; /* at first clear this;					      otherwise the changes will be ignored */		for (i = 0; i < CM_SAVED_MIXERS; i++) {			struct snd_kcontrol *ctl = cm->mixer_res_ctl[i];			if (ctl) {				int event;				memset(val, 0, sizeof(*val));				ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;				ctl->get(ctl, val);				event = SNDRV_CTL_EVENT_MASK_INFO;				if (val->value.integer.value[0] != cm->mixer_res_status[i]) {					val->value.integer.value[0] = cm->mixer_res_status[i];					ctl->put(ctl, val);					event |= SNDRV_CTL_EVENT_MASK_VALUE;				}				snd_ctl_notify(cm->card, event, &ctl->id);			}		}		kfree(val);	}}/* spinlock held! */static void setup_ac3(struct cmipci *cm, struct snd_pcm_substream *subs, int do_ac3, int rate){	if (do_ac3) {		/* AC3EN for 037 */		snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_AC3EN1);		/* AC3EN for 039 */		snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_AC3EN2);			if (cm->can_ac3_hw) {			/* SPD24SEL for 037, 0x02 */			/* SPD24SEL for 039, 0x20, but cannot be set */			snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);		} else { /* can_ac3_sw */			/* SPD32SEL for 037 & 039, 0x20 */			snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);			/* set 176K sample rate to fix 033 HW bug */			if (cm->chip_version == 33) {				if (rate >= 48000) {					snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);				} else {					snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);				}			}		}	} else {		snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_AC3EN1);		snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_AC3EN2);		if (cm->can_ac3_hw) {			/* chip model >= 37 */			if (snd_pcm_format_width(subs->runtime->format) > 16) {				snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);				snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);			} else {				snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);				snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);			}		} else {			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);		}	}}static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *subs, int up, int do_ac3){	int rate, err;	rate = subs->runtime->rate;	if (up && do_ac3)		if ((err = save_mixer_state(cm)) < 0)			return err;	spin_lock_irq(&cm->reg_lock);	cm->spdif_playback_avail = up;	if (up) {		/* they are controlled via "IEC958 Output Switch" */		/* snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT); */		/* snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_SPDO2DAC); */		if (cm->spdif_playback_enabled)			snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF);		setup_ac3(cm, subs, do_ac3, rate);		if (rate == 48000 || rate == 96000)			snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97);		else			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97);		if (rate > 48000)			snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);		else			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);	} else {		/* they are controlled via "IEC958 Output Switch" */		/* snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT); */		/* snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_SPDO2DAC); */		snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF);		setup_ac3(cm, subs, 0, 0);	}	spin_unlock_irq(&cm->reg_lock);	return 0;}

⌨️ 快捷键说明

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