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

📄 cs4231.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	snd_cs4231_mce_down(chip);	spin_lock_irqsave(&chip->lock, flags);	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */		snd_cs4231_out(chip, i, *ptr++);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_up(chip);	snd_cs4231_mce_down(chip);	mdelay(2);	return 0;		/* all things are ok.. */}static struct snd_pcm_hardware snd_cs4231_playback = {	.info			= SNDRV_PCM_INFO_MMAP |				  SNDRV_PCM_INFO_INTERLEAVED |				  SNDRV_PCM_INFO_MMAP_VALID |				  SNDRV_PCM_INFO_SYNC_START,	.formats		= SNDRV_PCM_FMTBIT_MU_LAW |				  SNDRV_PCM_FMTBIT_A_LAW |				  SNDRV_PCM_FMTBIT_IMA_ADPCM |				  SNDRV_PCM_FMTBIT_U8 |				  SNDRV_PCM_FMTBIT_S16_LE |				  SNDRV_PCM_FMTBIT_S16_BE,	.rates			= SNDRV_PCM_RATE_KNOT |				  SNDRV_PCM_RATE_8000_48000,	.rate_min		= 5510,	.rate_max		= 48000,	.channels_min		= 1,	.channels_max		= 2,	.buffer_bytes_max	= 32 * 1024,	.period_bytes_min	= 64,	.period_bytes_max	= 32 * 1024,	.periods_min		= 1,	.periods_max		= 1024,};static struct snd_pcm_hardware snd_cs4231_capture = {	.info			= SNDRV_PCM_INFO_MMAP |				  SNDRV_PCM_INFO_INTERLEAVED |				  SNDRV_PCM_INFO_MMAP_VALID |				  SNDRV_PCM_INFO_SYNC_START,	.formats		= SNDRV_PCM_FMTBIT_MU_LAW |				  SNDRV_PCM_FMTBIT_A_LAW |				  SNDRV_PCM_FMTBIT_IMA_ADPCM |				  SNDRV_PCM_FMTBIT_U8 |				  SNDRV_PCM_FMTBIT_S16_LE |				  SNDRV_PCM_FMTBIT_S16_BE,	.rates			= SNDRV_PCM_RATE_KNOT |				  SNDRV_PCM_RATE_8000_48000,	.rate_min		= 5510,	.rate_max		= 48000,	.channels_min		= 1,	.channels_max		= 2,	.buffer_bytes_max	= 32 * 1024,	.period_bytes_min	= 64,	.period_bytes_max	= 32 * 1024,	.periods_min		= 1,	.periods_max		= 1024,};static int snd_cs4231_playback_open(struct snd_pcm_substream *substream){	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_playback;	err = snd_cs4231_open(chip, CS4231_MODE_PLAY);	if (err < 0) {		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->playback_substream = substream;	chip->p_periods_sent = 0;	snd_pcm_set_sync(substream);	snd_cs4231_xrate(runtime);	return 0;}static int snd_cs4231_capture_open(struct snd_pcm_substream *substream){	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_capture;	err = snd_cs4231_open(chip, CS4231_MODE_RECORD);	if (err < 0) {		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->capture_substream = substream;	chip->c_periods_sent = 0;	snd_pcm_set_sync(substream);	snd_cs4231_xrate(runtime);	return 0;}static int snd_cs4231_playback_close(struct snd_pcm_substream *substream){	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);	snd_cs4231_close(chip, CS4231_MODE_PLAY);	chip->playback_substream = NULL;	return 0;}static int snd_cs4231_capture_close(struct snd_pcm_substream *substream){	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);	snd_cs4231_close(chip, CS4231_MODE_RECORD);	chip->capture_substream = NULL;	return 0;}/* XXX We can do some power-management, in particular on EBUS using * XXX the audio AUXIO register... */static struct snd_pcm_ops snd_cs4231_playback_ops = {	.open		=	snd_cs4231_playback_open,	.close		=	snd_cs4231_playback_close,	.ioctl		=	snd_pcm_lib_ioctl,	.hw_params	=	snd_cs4231_playback_hw_params,	.hw_free	=	snd_pcm_lib_free_pages,	.prepare	=	snd_cs4231_playback_prepare,	.trigger	=	snd_cs4231_trigger,	.pointer	=	snd_cs4231_playback_pointer,};static struct snd_pcm_ops snd_cs4231_capture_ops = {	.open		=	snd_cs4231_capture_open,	.close		=	snd_cs4231_capture_close,	.ioctl		=	snd_pcm_lib_ioctl,	.hw_params	=	snd_cs4231_capture_hw_params,	.hw_free	=	snd_pcm_lib_free_pages,	.prepare	=	snd_cs4231_capture_prepare,	.trigger	=	snd_cs4231_trigger,	.pointer	=	snd_cs4231_capture_pointer,};static int __init snd_cs4231_pcm(struct snd_card *card){	struct snd_cs4231 *chip = card->private_data;	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(card, "CS4231", 0, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,			&snd_cs4231_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,			&snd_cs4231_capture_ops);	/* global setup */	pcm->private_data = chip;	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;	strcpy(pcm->name, "CS4231");	chip->p_dma.preallocate(chip, pcm);	chip->pcm = pcm;	return 0;}static int __init snd_cs4231_timer(struct snd_card *card){	struct snd_cs4231 *chip = card->private_data;	struct snd_timer *timer;	struct snd_timer_id tid;	int err;	/* Timer initialization */	tid.dev_class = SNDRV_TIMER_CLASS_CARD;	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;	tid.card = card->number;	tid.device = 0;	tid.subdevice = 0;	err = snd_timer_new(card, "CS4231", &tid, &timer);	if (err < 0)		return err;	strcpy(timer->name, "CS4231");	timer->private_data = chip;	timer->hw = snd_cs4231_timer_table;	chip->timer = timer;	return 0;}/* *  MIXER part */static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol,			       struct snd_ctl_elem_info *uinfo){	static char *texts[4] = {		"Line", "CD", "Mic", "Mix"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 2;	uinfo->value.enumerated.items = 4;	if (uinfo->value.enumerated.item > 3)		uinfo->value.enumerated.item = 3;	strcpy(uinfo->value.enumerated.name,		texts[uinfo->value.enumerated.item]);	return 0;}static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.enumerated.item[0] =		(chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;	ucontrol->value.enumerated.item[1] =		(chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	unsigned short left, right;	int change;	if (ucontrol->value.enumerated.item[0] > 3 ||	    ucontrol->value.enumerated.item[1] > 3)		return -EINVAL;	left = ucontrol->value.enumerated.item[0] << 6;	right = ucontrol->value.enumerated.item[1] << 6;	spin_lock_irqsave(&chip->lock, flags);	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;	change = left != chip->image[CS4231_LEFT_INPUT] ||		 right != chip->image[CS4231_RIGHT_INPUT];	snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}static int snd_cs4231_info_single(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	uinfo->type = (mask == 1) ?		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_cs4231_get_single(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert)		ucontrol->value.integer.value[0] =			(mask - ucontrol->value.integer.value[0]);	return 0;}static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	int change;	unsigned short val;	val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	val <<= shift;	spin_lock_irqsave(&chip->lock, flags);	val = (chip->image[reg] & ~(mask << shift)) | val;	change = val != chip->image[reg];	snd_cs4231_out(chip, reg, val);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}static int snd_cs4231_info_double(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 24) & 0xff;	uinfo->type = mask == 1 ?		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_cs4231_get_double(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;	spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] =		(chip->image[left_reg] >> shift_left) & mask;	ucontrol->value.integer.value[1] =		(chip->image[right_reg] >> shift_right) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert) {		ucontrol->value.integer.value[0] =			(mask - ucontrol->value.integer.value[0]);		ucontrol->value.integer.value[1] =			(mask - ucontrol->value.integer.value[1]);	}	return 0;}static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;	int change;	unsigned short val1, val2;	val1 = ucontrol->value.integer.value[0] & mask;	val2 = ucontrol->value.integer.value[1] & mask;	if (invert) {		val1 = mask - val1;		val2 = mask - val2;	}	val1 <<= shift_left;	val2 <<= shift_right;	spin_lock_irqsave(&chip->lock, flags);	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;	change = val1 != chip->image[left_reg];	change |= val2 != chip->image[right_reg];	snd_cs4231_out(chip, left_reg, val1);	snd_cs4231_out(chip, right_reg, val2);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \  .info = snd_cs4231_info_single,	\  .get = snd_cs4231_get_single, .put = snd_cs4231_put_single,	\  .private_value = (reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) }#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, \			shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \  .info = snd_cs4231_info_double,	\  .get = snd_cs4231_get_double, .put = snd_cs4231_put_double,	\  .private_value = (left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | \		   ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22) }static struct snd_kcontrol_new snd_cs4231_controls[] __initdata = {CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT,		CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT,		CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN,		CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN,		CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT,		CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT,		CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT,		CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT,		CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0,		15, 0),{	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,	.name	= "Capture Source",	.info	= snd_cs4231_info_mux,	.get	= snd_cs4231_get_mux,	.put	= snd_cs4231_put_mux,},CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5,		1, 0),CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1),/* SPARC specific uses of XCTL{0,1} general purpose outputs.  */CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1),CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1)};static int __init snd_cs4231_mixer(struct snd_card *card){	struct snd_cs4231 *chip = card->private_data;	int err, idx;	snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);	strcpy(card->mixername, chip->pcm->name);	for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {		err = snd_ctl_add(card,				 snd_ctl_new1(&snd_cs4231_controls[idx], chip));		if (err < 0)			return err;	}	return 0;}static int dev;static int __init cs4231_attach_begin(struct snd_card **rcard){	struct snd_card *card;	struct snd_cs4231 *chip;	*rcard = NULL;	if (dev >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev]) {		dev++;		return -ENOENT;	}	card = snd_card_new(index[dev], id[dev], THIS_MODULE,			    sizeof(struct snd_cs4231));	if (card == NULL)		return -ENOMEM;	strcpy(card->driver, "CS4231");	strcpy(card->shortname, "Sun CS4231");	chip = card->private_data;	chip->card = card;	*rcard = card;	return 0;}static int __init cs4231_attach_finish(struct snd_card *card){	struct snd_cs4231 *chip = card->private_data;	int err;	err = snd_cs4231_pcm(card);	if (err < 0)		goto out_err;	err = snd_cs4231_mixer(card);	if (err < 0)		goto out_err;	err = snd_cs4231_timer(card);	if (err < 0)		goto out_err;	err = snd_card_register(card);	if (err < 0)		goto out_err;

⌨️ 快捷键说明

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