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

📄 atiixp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	} while (timeout-- > 0);	atiixp_spdif_enable_transfer(chip, 0);}/* set up slots and formats for SPDIF OUT */static int snd_atiixp_spdif_prepare(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	spin_lock_irq(&chip->reg_lock);	if (chip->spdif_over_aclink) {		unsigned int data;		/* enable slots 10/11 */		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK,			      ATI_REG_CMD_SPDF_CONFIG_01);		data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK;		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |			ATI_REG_OUT_DMA_SLOT_BIT(11);		data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;		atiixp_write(chip, OUT_DMA_SLOT, data);		atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT,			      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?			      ATI_REG_CMD_INTERLEAVE_OUT : 0);	} else {		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0);		atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, 0);	}	spin_unlock_irq(&chip->reg_lock);	return 0;}/* set up slots and formats for analog OUT */static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	unsigned int data;	spin_lock_irq(&chip->reg_lock);	data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK;	switch (substream->runtime->channels) {	case 8:		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |			ATI_REG_OUT_DMA_SLOT_BIT(11);		/* fallthru */	case 6:		data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |			ATI_REG_OUT_DMA_SLOT_BIT(8);		/* fallthru */	case 4:		data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |			ATI_REG_OUT_DMA_SLOT_BIT(9);		/* fallthru */	default:		data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |			ATI_REG_OUT_DMA_SLOT_BIT(4);		break;	}	/* set output threshold */	data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;	atiixp_write(chip, OUT_DMA_SLOT, data);	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT,		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?		      ATI_REG_CMD_INTERLEAVE_OUT : 0);	/*	 * enable 6 channel re-ordering bit if needed	 */	atiixp_update(chip, 6CH_REORDER, ATI_REG_6CH_REORDER_EN,		      substream->runtime->channels >= 6 ? ATI_REG_6CH_REORDER_EN: 0);    	spin_unlock_irq(&chip->reg_lock);	return 0;}/* set up slots and formats for analog IN */static int snd_atiixp_capture_prepare(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	spin_lock_irq(&chip->reg_lock);	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_IN,		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?		      ATI_REG_CMD_INTERLEAVE_IN : 0);	spin_unlock_irq(&chip->reg_lock);	return 0;}/* * hw_params - allocate the buffer and set up buffer descriptors */static int snd_atiixp_pcm_hw_params(struct snd_pcm_substream *substream,				    struct snd_pcm_hw_params *hw_params){	struct atiixp *chip = snd_pcm_substream_chip(substream);	struct atiixp_dma *dma = substream->runtime->private_data;	int err;	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));	if (err < 0)		return err;	dma->buf_addr = substream->runtime->dma_addr;	dma->buf_bytes = params_buffer_bytes(hw_params);	err = atiixp_build_dma_packets(chip, dma, substream,				       params_periods(hw_params),				       params_period_bytes(hw_params));	if (err < 0)		return err;	if (dma->ac97_pcm_type >= 0) {		struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type];		/* PCM is bound to AC97 codec(s)		 * set up the AC97 codecs		 */		if (dma->pcm_open_flag) {			snd_ac97_pcm_close(pcm);			dma->pcm_open_flag = 0;		}		err = snd_ac97_pcm_open(pcm, params_rate(hw_params),					params_channels(hw_params),					pcm->r[0].slots);		if (err >= 0)			dma->pcm_open_flag = 1;	}	return err;}static int snd_atiixp_pcm_hw_free(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	struct atiixp_dma *dma = substream->runtime->private_data;	if (dma->pcm_open_flag) {		struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type];		snd_ac97_pcm_close(pcm);		dma->pcm_open_flag = 0;	}	atiixp_clear_dma_packets(chip, dma, substream);	snd_pcm_lib_free_pages(substream);	return 0;}/* * pcm hardware definition, identical for all DMA types */static struct snd_pcm_hardware snd_atiixp_pcm_hw ={	.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 | SNDRV_PCM_FMTBIT_S32_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	256 * 1024,	.period_bytes_min =	32,	.period_bytes_max =	128 * 1024,	.periods_min =		2,	.periods_max =		ATI_MAX_DESCRIPTORS,};static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,			       struct atiixp_dma *dma, int pcm_type){	struct atiixp *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);	if (dma->opened)		return -EBUSY;	dma->substream = substream;	runtime->hw = snd_atiixp_pcm_hw;	dma->ac97_pcm_type = pcm_type;	if (pcm_type >= 0) {		runtime->hw.rates = chip->pcms[pcm_type]->rates;		snd_pcm_limit_hw_rates(runtime);	} else {		/* direct SPDIF */		runtime->hw.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;	}	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;	runtime->private_data = dma;	/* enable DMA bits */	spin_lock_irq(&chip->reg_lock);	dma->ops->enable_dma(chip, 1);	spin_unlock_irq(&chip->reg_lock);	dma->opened = 1;	return 0;}static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,				struct atiixp_dma *dma){	struct atiixp *chip = snd_pcm_substream_chip(substream);	/* disable DMA bits */	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);	spin_lock_irq(&chip->reg_lock);	dma->ops->enable_dma(chip, 0);	spin_unlock_irq(&chip->reg_lock);	dma->substream = NULL;	dma->opened = 0;	return 0;}/* */static int snd_atiixp_playback_open(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	int err;	mutex_lock(&chip->open_mutex);	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);	mutex_unlock(&chip->open_mutex);	if (err < 0)		return err;	substream->runtime->hw.channels_max = chip->max_channels;	if (chip->max_channels > 2)		/* channels must be even */		snd_pcm_hw_constraint_step(substream->runtime, 0,					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);	return 0;}static int snd_atiixp_playback_close(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	int err;	mutex_lock(&chip->open_mutex);	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);	mutex_unlock(&chip->open_mutex);	return err;}static int snd_atiixp_capture_open(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1);}static int snd_atiixp_capture_close(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]);}static int snd_atiixp_spdif_open(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	int err;	mutex_lock(&chip->open_mutex);	if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);	else		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);	mutex_unlock(&chip->open_mutex);	return err;}static int snd_atiixp_spdif_close(struct snd_pcm_substream *substream){	struct atiixp *chip = snd_pcm_substream_chip(substream);	int err;	mutex_lock(&chip->open_mutex);	if (chip->spdif_over_aclink)		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);	else		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);	mutex_unlock(&chip->open_mutex);	return err;}/* AC97 playback */static struct snd_pcm_ops snd_atiixp_playback_ops = {	.open =		snd_atiixp_playback_open,	.close =	snd_atiixp_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_playback_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};/* AC97 capture */static struct snd_pcm_ops snd_atiixp_capture_ops = {	.open =		snd_atiixp_capture_open,	.close =	snd_atiixp_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_capture_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};/* SPDIF playback */static struct snd_pcm_ops snd_atiixp_spdif_ops = {	.open =		snd_atiixp_spdif_open,	.close =	snd_atiixp_spdif_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_spdif_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = {	/* front PCM */	{		.exclusive = 1,		.r = {	{				.slots = (1 << AC97_SLOT_PCM_LEFT) |					 (1 << AC97_SLOT_PCM_RIGHT) |					 (1 << AC97_SLOT_PCM_CENTER) |					 (1 << AC97_SLOT_PCM_SLEFT) |					 (1 << AC97_SLOT_PCM_SRIGHT) |					 (1 << AC97_SLOT_LFE)			}		}	},	/* PCM IN #1 */	{		.stream = 1,		.exclusive = 1,		.r = {	{				.slots = (1 << AC97_SLOT_PCM_LEFT) |					 (1 << AC97_SLOT_PCM_RIGHT)			}		}	},	/* S/PDIF OUT (optional) */	{		.exclusive = 1,		.spdif = 1,		.r = {	{				.slots = (1 << AC97_SLOT_SPDIF_LEFT2) |					 (1 << AC97_SLOT_SPDIF_RIGHT2)			}		}	},};static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {	.type = ATI_DMA_PLAYBACK,	.llp_offset = ATI_REG_OUT_DMA_LINKPTR,	.dt_cur = ATI_REG_OUT_DMA_DT_CUR,	.enable_dma = atiixp_out_enable_dma,	.enable_transfer = atiixp_out_enable_transfer,	.flush_dma = atiixp_out_flush_dma,};	static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {	.type = ATI_DMA_CAPTURE,	.llp_offset = ATI_REG_IN_DMA_LINKPTR,	.dt_cur = ATI_REG_IN_DMA_DT_CUR,	.enable_dma = atiixp_in_enable_dma,	.enable_transfer = atiixp_in_enable_transfer,	.flush_dma = atiixp_in_flush_dma,};	static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {	.type = ATI_DMA_SPDIF,	.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,	.dt_cur = ATI_REG_SPDF_DMA_DT_CUR,	.enable_dma = atiixp_spdif_enable_dma,	.enable_transfer = atiixp_spdif_enable_transfer,	.flush_dma = atiixp_spdif_flush_dma,};	static int __devinit snd_atiixp_pcm_new(struct atiixp *chip){	struct snd_pcm *pcm;	struct snd_ac97_bus *pbus = chip->ac97_bus;	int err, i, num_pcms;	/* initialize constants */	chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;	chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;	if (! chip->spdif_over_aclink)		chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops;	/* assign AC97 pcm */	if (chip->spdif_over_aclink)		num_pcms = 3;	else		num_pcms = 2;	err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs);	if (err < 0)		return err;	for (i = 0; i < num_pcms; i++)		chip->pcms[i] = &pbus->pcms[i];	chip->max_channels = 2;	if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {		if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_LFE))			chip->max_channels = 6;		else			chip->max_channels = 4;	}	/* PCM #0: analog I/O */	err = snd_pcm_new(chip->card, "ATI IXP AC97",			  ATI_PCMDEV_ANALOG, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);	pcm->private_data = chip;	strcpy(pcm->name, "ATI IXP AC97");	chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,

⌨️ 快捷键说明

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