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

📄 cmipci.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * preparation *//* playback - enable spdif only on the certain condition */static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	int rate = substream->runtime->rate;	int err, do_spdif, do_ac3 = 0;	do_spdif = (rate >= 44100 &&		    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(struct snd_pcm_substream *substream){	struct cmipci *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);}/* * Apparently, the samples last played on channel A stay in some buffer, even * after the channel is reset, and get added to the data for the rear DACs when * playing a multichannel stream on channel B.  This is likely to generate * wraparounds and thus distortions. * To avoid this, we play at least one zero sample after the actual stream has * stopped. */static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec){	struct snd_pcm_runtime *runtime = rec->substream->runtime;	unsigned int reg, val;	if (rec->needs_silencing && runtime && runtime->dma_area) {		/* set up a small silence buffer */		memset(runtime->dma_area, 0, PAGE_SIZE);		reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2;		val = ((PAGE_SIZE / 4) - 1) | (((PAGE_SIZE / 4) / 2 - 1) << 16);		snd_cmipci_write(cm, reg, val);			/* configure for 16 bits, 2 channels, 8 kHz */		if (runtime->channels > 2)			set_dac_channels(cm, rec, 2);		spin_lock_irq(&cm->reg_lock);		val = snd_cmipci_read(cm, CM_REG_FUNCTRL1);		val &= ~(CM_ASFC_MASK << (rec->ch * 3));		val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3);		snd_cmipci_write(cm, CM_REG_FUNCTRL1, val);		val = snd_cmipci_read(cm, CM_REG_CHFORMAT);		val &= ~(CM_CH0FMT_MASK << (rec->ch * 2));		val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2);		if (cm->chip_version == 68) {			val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2));			val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2));		}		snd_cmipci_write(cm, CM_REG_CHFORMAT, val);			/* start stream (we don't need interrupts) */		cm->ctrl |= CM_CHEN0 << rec->ch;		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);		spin_unlock_irq(&cm->reg_lock);		msleep(1);		/* stop and reset stream */		spin_lock_irq(&cm->reg_lock);		cm->ctrl &= ~(CM_CHEN0 << rec->ch);		val = CM_RST_CH0 << rec->ch;		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val);		snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val);		spin_unlock_irq(&cm->reg_lock);		rec->needs_silencing = 0;	}}static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	setup_spdif_playback(cm, substream, 0, 0);	restore_mixer_state(cm);	snd_cmipci_silence_hack(cm, &cm->channel[0]);	return snd_cmipci_hw_free(substream);}static int snd_cmipci_playback2_hw_free(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	snd_cmipci_silence_hack(cm, &cm->channel[1]);	return snd_cmipci_hw_free(substream);}/* capture */static int snd_cmipci_capture_prepare(struct snd_pcm_substream *substream){	struct cmipci *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(struct snd_pcm_substream *substream){	struct cmipci *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(struct snd_pcm_substream *subs){	struct cmipci *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 cmipci *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;	snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask);	snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask);	spin_unlock(&cm->reg_lock);	if (cm->rmidi && (status & CM_UARTINT))		snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data);	if (cm->pcm) {		if ((status & CM_CHINT0) && cm->channel[0].running)			snd_pcm_period_elapsed(cm->channel[0].substream);		if ((status & CM_CHINT1) && cm->channel[1].running)			snd_pcm_period_elapsed(cm->channel[1].substream);	}	return IRQ_HANDLED;}/* * h/w infos *//* playback on channel A */static struct snd_pcm_hardware snd_cmipci_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5512,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* capture on channel B */static struct snd_pcm_hardware snd_cmipci_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5512,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* playback on channel B - stereo 16bit only? */static struct snd_pcm_hardware snd_cmipci_playback2 ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5512,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* spdif playback on channel A */static struct snd_pcm_hardware snd_cmipci_playback_spdif ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,	.rate_min =		44100,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* spdif playback on channel A (32bit, IEC958 subframes) */static struct snd_pcm_hardware snd_cmipci_playback_iec958_subframe ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,	.rate_min =		44100,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* spdif capture on channel B */static struct snd_pcm_hardware snd_cmipci_capture_spdif ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),	.formats =	        SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,	.rate_min =		44100,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		1024,	.fifo_size =		0,};/* * check device open/close */static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substream *subs){	int ch = mode & CM_OPEN_CH_MASK;	/* FIXME: a file should wait until the device becomes free	 * when it's opened on blocking mode.  however, since the current	 * pcm framework doesn't pass file pointer before actually opened,	 * we can't know whether blocking mode or not in open callback..	 */	mutex_lock(&cm->open_mutex);	if (cm->opened[ch]) {		mutex_unlock(&cm->open_mutex);		return -EBUSY;	}	cm->opened[ch] = mode;	cm->channel[ch].substream = subs;	if (! (mode & CM_OPEN_DAC)) {		/* disable dual DAC mode */		cm->channel[ch].is_dac = 0;		spin_lock_irq(&cm->reg_lock);		snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);		spin_unlock_irq(&cm->reg_lock);	}	mutex_unlock(&cm->open_mutex);	return 0;}static void close_device_check(struct cmipci *cm, int mode){	int ch = mode & CM_OPEN_CH_MASK;	mutex_lock(&cm->open_mutex);	if (cm->opened[ch] == mode) {		if (cm->channel[ch].substream) {			snd_cmipci_ch_reset(cm, ch);			cm->channel[ch].running = 0;			cm->channel[ch].substream = NULL;		}		cm->opened[ch] = 0;		if (! cm->channel[ch].is_dac) {			/* enable dual DAC mode again */			cm->channel[ch].is_dac = 1;			spin_lock_irq(&cm->reg_lock);			snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);			spin_unlock_irq(&cm->reg_lock);		}	}	mutex_unlock(&cm->open_mutex);}/* */static int snd_cmipci_playback_open(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0)		return err;	runtime->hw = snd_cmipci_playback;	if (cm->chip_version == 68) {		runtime->hw.rates |= SNDRV_PCM_RATE_88200 |				     SNDRV_PCM_RATE_96000;		runtime->hw.rate_max = 96000;	}	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);	cm->dig_pcm_status = cm->dig_status;	return 0;}static int snd_cmipci_capture_open(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	if ((err = open_device_check(cm, CM_OPEN_CAPTURE, substream)) < 0)		return err;	runtime->hw = snd_cmipci_capture;	if (cm->chip_version == 68) {	// 8768 only supports 44k/48k recording		runtime->hw.rate_min = 41000;		runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;	}	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);	return 0;}static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */		return err;	runtime->hw = snd_cmipci_playback2;	mutex_lock(&cm->open_mutex);	if (! cm->opened[CM_CH_PLAY]) {		if (cm->can_multi_ch) {			runtime->hw.channels_max = cm->max_channels;			if (cm->max_channels == 4)				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_4);			else if (cm->max_channels == 6)				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_6);			else if (cm->max_channels == 8)				snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8);		}	}	mutex_unlock(&cm->open_mutex);	if (cm->chip_version == 68) {		runtime->hw.rates |= SNDRV_PCM_RATE_88200 |				     SNDRV_PCM_RATE_96000;		runtime->hw.rate_max = 96000;	}	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);	return 0;}

⌨️ 快捷键说明

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