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

📄 soc-core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return ret;platform_err:	if (cpu_dai->ops.hw_free)		cpu_dai->ops.hw_free(substream);interface_err:	if (codec_dai->ops.hw_free)		codec_dai->ops.hw_free(substream);codec_err:	if(machine->ops && machine->ops->hw_free)		machine->ops->hw_free(substream);	mutex_unlock(&pcm_mutex);	return ret;}/* * Free's resources allocated by hw_params, can be called multiple times */static int soc_pcm_hw_free(struct snd_pcm_substream *substream){	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_dai_link *machine = rtd->dai;	struct snd_soc_platform *platform = socdev->platform;	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;	struct snd_soc_codec *codec = socdev->codec;	mutex_lock(&pcm_mutex);	/* apply codec digital mute */	if (!codec->active && codec_dai->dai_ops.digital_mute)		codec_dai->dai_ops.digital_mute(codec_dai, 1);	/* free any machine hw params */	if (machine->ops && machine->ops->hw_free)		machine->ops->hw_free(substream);	/* free any DMA resources */	if (platform->pcm_ops->hw_free)		platform->pcm_ops->hw_free(substream);	/* now free hw params for the DAI's  */	if (codec_dai->ops.hw_free)		codec_dai->ops.hw_free(substream);	if (cpu_dai->ops.hw_free)		cpu_dai->ops.hw_free(substream);	mutex_unlock(&pcm_mutex);	return 0;}static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_dai_link *machine = rtd->dai;	struct snd_soc_platform *platform = socdev->platform;	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;	int ret;	if (codec_dai->ops.trigger) {		ret = codec_dai->ops.trigger(substream, cmd);		if (ret < 0)			return ret;	}	if (platform->pcm_ops->trigger) {		ret = platform->pcm_ops->trigger(substream, cmd);		if (ret < 0)			return ret;	}	if (cpu_dai->ops.trigger) {		ret = cpu_dai->ops.trigger(substream, cmd);		if (ret < 0)			return ret;	}	return 0;}/* ASoC PCM operations */static struct snd_pcm_ops soc_pcm_ops = {	.open		= soc_pcm_open,	.close		= soc_codec_close,	.hw_params	= soc_pcm_hw_params,	.hw_free	= soc_pcm_hw_free,	.prepare	= soc_pcm_prepare,	.trigger	= soc_pcm_trigger,};#ifdef CONFIG_PM/* powers down audio subsystem for suspend */static int soc_suspend(struct platform_device *pdev, pm_message_t state){ 	struct snd_soc_device *socdev = platform_get_drvdata(pdev); 	struct snd_soc_machine *machine = socdev->machine; 	struct snd_soc_platform *platform = socdev->platform; 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;	struct snd_soc_codec *codec = socdev->codec;	int i;	/* mute any active DAC's */	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;		if (dai->dai_ops.digital_mute && dai->playback.active)			dai->dai_ops.digital_mute(dai, 1);	}	if (machine->suspend_pre)		machine->suspend_pre(pdev, state);	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai  *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)			cpu_dai->suspend(pdev, cpu_dai);		if (platform->suspend)			platform->suspend(pdev, cpu_dai);	}	/* close any waiting streams and save state */	run_delayed_work(&socdev->delayed_work);	codec->suspend_dapm_state = codec->dapm_state;	for(i = 0; i < codec->num_dai; i++) {		char *stream = codec->dai[i].playback.stream_name;		if (stream != NULL)			snd_soc_dapm_stream_event(codec, stream,				SND_SOC_DAPM_STREAM_SUSPEND);		stream = codec->dai[i].capture.stream_name;		if (stream != NULL)			snd_soc_dapm_stream_event(codec, stream,				SND_SOC_DAPM_STREAM_SUSPEND);	}	if (codec_dev->suspend)		codec_dev->suspend(pdev, state);	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)			cpu_dai->suspend(pdev, cpu_dai);	}	if (machine->suspend_post)		machine->suspend_post(pdev, state);	return 0;}/* powers up audio subsystem after a suspend */static int soc_resume(struct platform_device *pdev){ 	struct snd_soc_device *socdev = platform_get_drvdata(pdev); 	struct snd_soc_machine *machine = socdev->machine; 	struct snd_soc_platform *platform = socdev->platform; 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;	struct snd_soc_codec *codec = socdev->codec;	int i;	if (machine->resume_pre)		machine->resume_pre(pdev);	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)			cpu_dai->resume(pdev, cpu_dai);	}	if (codec_dev->resume)		codec_dev->resume(pdev);	for(i = 0; i < codec->num_dai; i++) {		char* stream = codec->dai[i].playback.stream_name;		if (stream != NULL)			snd_soc_dapm_stream_event(codec, stream,				SND_SOC_DAPM_STREAM_RESUME);		stream = codec->dai[i].capture.stream_name;		if (stream != NULL)			snd_soc_dapm_stream_event(codec, stream,				SND_SOC_DAPM_STREAM_RESUME);	}	/* unmute any active DAC's */	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;		if (dai->dai_ops.digital_mute && dai->playback.active)			dai->dai_ops.digital_mute(dai, 0);	}	for(i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)			cpu_dai->resume(pdev, cpu_dai);		if (platform->resume)			platform->resume(pdev, cpu_dai);	}	if (machine->resume_post)		machine->resume_post(pdev);	return 0;}#else#define soc_suspend	NULL#define soc_resume	NULL#endif/* probes a new socdev */static int soc_probe(struct platform_device *pdev){	int ret = 0, i;	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_machine *machine = socdev->machine;	struct snd_soc_platform *platform = socdev->platform;	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;	if (machine->probe) {		ret = machine->probe(pdev);		if(ret < 0)			return ret;	}	for (i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->probe) {			ret = cpu_dai->probe(pdev);			if(ret < 0)				goto cpu_dai_err;		}	}	if (codec_dev->probe) {		ret = codec_dev->probe(pdev);		if(ret < 0)			goto cpu_dai_err;	}	if (platform->probe) {		ret = platform->probe(pdev);		if(ret < 0)			goto platform_err;	}	/* DAPM stream work */	INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);	return 0;platform_err:	if (codec_dev->remove)		codec_dev->remove(pdev);cpu_dai_err:	for (i--; i >= 0; i--) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->remove)			cpu_dai->remove(pdev);	}	if (machine->remove)		machine->remove(pdev);	return ret;}/* removes a socdev */static int soc_remove(struct platform_device *pdev){	int i;	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_machine *machine = socdev->machine;	struct snd_soc_platform *platform = socdev->platform;	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;	run_delayed_work(&socdev->delayed_work);	if (platform->remove)		platform->remove(pdev);	if (codec_dev->remove)		codec_dev->remove(pdev);	for (i = 0; i < machine->num_links; i++) {		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;		if (cpu_dai->remove)			cpu_dai->remove(pdev);	}	if (machine->remove)		machine->remove(pdev);	return 0;}/* ASoC platform driver */static struct platform_driver soc_driver = {	.driver		= {		.name		= "soc-audio",	},	.probe		= soc_probe,	.remove		= soc_remove,	.suspend	= soc_suspend,	.resume		= soc_resume,};/* create a new pcm */static int soc_new_pcm(struct snd_soc_device *socdev,	struct snd_soc_dai_link *dai_link, int num){	struct snd_soc_codec *codec = socdev->codec;	struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai;	struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai;	struct snd_soc_pcm_runtime *rtd;	struct snd_pcm *pcm;	char new_name[64];	int ret = 0, playback = 0, capture = 0;	rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);	if (rtd == NULL)		return -ENOMEM;	rtd->dai = dai_link;	rtd->socdev = socdev;	codec_dai->codec = socdev->codec;	/* check client and interface hw capabilities */	sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name,		get_dai_name(cpu_dai->type), num);	if (codec_dai->playback.channels_min)		playback = 1;	if (codec_dai->capture.channels_min)		capture = 1;	ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,		capture, &pcm);	if (ret < 0) {		printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);		kfree(rtd);		return ret;	}	pcm->private_data = rtd;	soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;	soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;	soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl;	soc_pcm_ops.copy = socdev->platform->pcm_ops->copy;	soc_pcm_ops.silence = socdev->platform->pcm_ops->silence;	soc_pcm_ops.ack = socdev->platform->pcm_ops->ack;	soc_pcm_ops.page = socdev->platform->pcm_ops->page;	if (playback)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);	if (capture)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);	ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm);	if (ret < 0) {		printk(KERN_ERR "asoc: platform pcm constructor failed\n");		kfree(rtd);		return ret;	}	pcm->private_free = socdev->platform->pcm_free;	printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,		cpu_dai->name);	return ret;}/* codec register dump */static ssize_t codec_reg_show(struct device *dev,	struct device_attribute *attr, char *buf){	struct snd_soc_device *devdata = dev_get_drvdata(dev);	struct snd_soc_codec *codec = devdata->codec;	int i, step = 1, count = 0;	if (!codec->reg_cache_size)		return 0;	if (codec->reg_cache_step)		step = codec->reg_cache_step;	count += sprintf(buf, "%s registers\n", codec->name);	for(i = 0; i < codec->reg_cache_size; i += step)		count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i));	return count;}static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);/** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec * @ops: AC97 bus operations * @num: AC97 codec number * * Initialises AC97 codec resources for use by ad-hoc devices only. */int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,	struct snd_ac97_bus_ops *ops, int num){	mutex_lock(&codec->mutex);	codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);	if (codec->ac97 == NULL) {		mutex_unlock(&codec->mutex);		return -ENOMEM;	}	codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);	if (codec->ac97->bus == NULL) {		kfree(codec->ac97);		codec->ac97 = NULL;		mutex_unlock(&codec->mutex);		return -ENOMEM;	}	codec->ac97->bus->ops = ops;	codec->ac97->num = num;	mutex_unlock(&codec->mutex);	return 0;}EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);/** * snd_soc_free_ac97_codec - free AC97 codec device * @codec: audio codec * * Frees AC97 codec device resources. */void snd_soc_free_ac97_codec(struct snd_soc_codec *codec){	mutex_lock(&codec->mutex);	kfree(codec->ac97->bus);	kfree(codec->ac97);	codec->ac97 = NULL;	mutex_unlock(&codec->mutex);}EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);/** * snd_soc_update_bits - update codec register bits * @codec: audio codec * @reg: codec register * @mask: register mask * @value: new value * * Writes new register value. * * Returns 1 for change else 0. */int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,				unsigned short mask, unsigned short value){	int change;	unsigned short old, new;	mutex_lock(&io_mutex);	old = snd_soc_read(codec, reg);	new = (old & ~mask) | value;	change = old != new;	if (change)		snd_soc_write(codec, reg, new);	mutex_unlock(&io_mutex);	return change;}EXPORT_SYMBOL_GPL(snd_soc_update_bits);/** * snd_soc_test_bits - test register for change * @codec: audio codec * @reg: codec register * @mask: register mask * @value: new value * * Tests a register with a new value and checks if the new value is * different from the old value. * * Returns 1 for change else 0. */int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,				unsigned short mask, unsigned short value){	int change;	unsigned short old, new;	mutex_lock(&io_mutex);	old = snd_soc_read(codec, reg);	new = (old & ~mask) | value;	change = old != new;	mutex_unlock(&io_mutex);	return change;}EXPORT_SYMBOL_GPL(snd_soc_test_bits);/** * snd_soc_new_pcms - create new sound card and pcms * @socdev: the SoC audio device * * Create a new sound card based upon the codec and interface pcms. * * Returns 0 for success, else error. */int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid){	struct snd_soc_codec *codec = socdev->codec;	struct snd_soc_machine *machine = socdev->machine;	int ret = 0, i;	mutex_lock(&codec->mutex);	/* register a sound card */	codec->card = snd_card_new(idx, xid, codec->owner, 0);	if (!codec->card) {		printk(KERN_ERR "asoc: can't create sound card for codec %s\n",			codec->name);		mutex_unlock(&codec->mutex);

⌨️ 快捷键说明

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