📄 soc-core.c
字号:
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 + -