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

📄 cmipci.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
 */static snd_pcm_uframes_t snd_cmipci_pcm_pointer(cmipci_t *cm, cmipci_pcm_t *rec,					  snd_pcm_substream_t *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(snd_pcm_substream_t *substream,				       int cmd){	cmipci_t *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], substream, cmd);}static snd_pcm_uframes_t snd_cmipci_playback_pointer(snd_pcm_substream_t *substream){	cmipci_t *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(snd_pcm_substream_t *substream,				     int cmd){	cmipci_t *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], substream, cmd);}static snd_pcm_uframes_t snd_cmipci_capture_pointer(snd_pcm_substream_t *substream){	cmipci_t *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(snd_kcontrol_t *kcontrol,					 snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_default_get(snd_kcontrol_t *kcontrol,					snd_ctl_elem_value_t *ucontrol){	cmipci_t *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(snd_kcontrol_t * kcontrol,					 snd_ctl_elem_value_t * ucontrol){	cmipci_t *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 snd_kcontrol_new_t 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(snd_kcontrol_t *kcontrol,				      snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,				     snd_ctl_elem_value_t *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 snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata ={	.access =	SNDRV_CTL_ELEM_ACCESS_READ,	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,	.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(snd_kcontrol_t *kcontrol,					snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_cmipci_spdif_stream_get(snd_kcontrol_t *kcontrol,				       snd_ctl_elem_value_t *ucontrol){	cmipci_t *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(snd_kcontrol_t *kcontrol,				       snd_ctl_elem_value_t *ucontrol){	cmipci_t *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 snd_kcontrol_new_t 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(cmipci_t *cm){	if (! cm->mixer_insensitive) {		snd_ctl_elem_value_t *val;		unsigned int i;		val = kmalloc(sizeof(*val), GFP_ATOMIC);		if (!val)			return -ENOMEM;		for (i = 0; i < CM_SAVED_MIXERS; i++) {			snd_kcontrol_t *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(cmipci_t *cm){	if (cm->mixer_insensitive) {		snd_ctl_elem_value_t *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++) {			snd_kcontrol_t *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(cmipci_t *cm, snd_pcm_substream_t *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(cmipci_t *cm, snd_pcm_substream_t *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)			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);	} 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_FUNCTRL1, CM_PLAYBACK_SPDF);		setup_ac3(cm, subs, 0, 0);	}	spin_unlock_irq(&cm->reg_lock);	return 0;}/* * preparation *//* playback - enable spdif only on the certain condition */static int snd_cmipci_playback_prepare(snd_pcm_substream_t *substream){	cmipci_t *cm = snd_pcm_substream_chip(substream);	int rate = substream->runtime->rate;	int err, do_spdif, do_ac3 = 0;	do_spdif = ((rate == 44100 || rate == 48000) &&		    substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE &&		    substream->runtime->channels == 2);	if (do_spdif && cm->can_ac3_hw) 		do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO;	if ((err = setup_spdif_playback(cm, substream, do_spdif, do_ac3)) < 0)		return err;	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream);}/* playback  (via device #2) - enable spdif always */static int snd_cmipci_playback_spdif_prepare(snd_pcm_substream_t *substream){	cmipci_t *cm = snd_pcm_substream_chip(substream);	int err, do_ac3;	if (cm->can_ac3_hw) 		do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO;	else		do_ac3 = 1; /* doesn't matter */	if ((err = setup_spdif_playback(cm, substream, 1, do_ac3)) < 0)		return err;	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream);}static int snd_cmipci_playback_hw_free(snd_pcm_substream_t *substream){	cmipci_t *cm = snd_pcm_substream_chip(substream);	setup_spdif_playback(cm, substream, 0, 0);	restore_mixer_state(cm);	return snd_cmipci_hw_free(substream);}/* capture */static int snd_cmipci_capture_prepare(snd_pcm_substream_t *substream){	cmipci_t *cm = snd_pcm_substream_chip(substream);	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream);}/* capture with spdif (via device #2) */static int snd_cmipci_capture_spdif_prepare(snd_pcm_substream_t *substream){	cmipci_t *cm = snd_pcm_substream_chip(substream);	spin_lock_irq(&cm->reg_lock);	snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);	spin_unlock_irq(&cm->reg_lock);	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream);}static int snd_cmipci_capture_spdif_hw_free(snd_pcm_substream_t *subs){	cmipci_t *cm = snd_pcm_substream_chip(subs);	spin_lock_irq(&cm->reg_lock);	snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);	spin_unlock_irq(&cm->reg_lock);	return snd_cmipci_hw_free(subs);}/* * interrupt handler */static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs){	cmipci_t *cm = dev_id;	unsigned int status, mask = 0;		/* fastpath out, to ease interrupt sharing */	status = snd_cmipci_read(cm, CM_REG_INT_STATUS);	if (!(status & CM_INTR))		return IRQ_NONE;	/* acknowledge interrupt */	spin_lock(&cm->reg_lock);	if (status & CM_CHINT0)		mask |= CM_CH0_INT_EN;	if (status & CM_CHINT1)		mask |= CM_CH1_INT_EN;

⌨️ 快捷键说明

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