📄 soc-core.c
字号:
return -ENODEV; } codec->card->dev = socdev->dev; codec->card->private_data = codec; strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ for(i = 0; i < machine->num_links; i++) { ret = soc_new_pcm(socdev, &machine->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", machine->dai_link[i].stream_name); mutex_unlock(&codec->mutex); return ret; } } mutex_unlock(&codec->mutex); return ret;}EXPORT_SYMBOL_GPL(snd_soc_new_pcms);/** * snd_soc_register_card - register sound card * @socdev: the SoC audio device * * Register a SoC sound card. Also registers an AC97 device if the * codec is AC97 for ad hoc devices. * * Returns 0 for success, else error. */int snd_soc_register_card(struct snd_soc_device *socdev){ struct snd_soc_codec *codec = socdev->codec; struct snd_soc_machine *machine = socdev->machine; int ret = 0, i, ac97 = 0, err = 0; mutex_lock(&codec->mutex); for(i = 0; i < machine->num_links; i++) { if (socdev->machine->dai_link[i].init) { err = socdev->machine->dai_link[i].init(codec); if (err < 0) { printk(KERN_ERR "asoc: failed to init %s\n", socdev->machine->dai_link[i].stream_name); continue; } } if (socdev->machine->dai_link[i].codec_dai->type == SND_SOC_DAI_AC97_BUS) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), "%s", machine->name); snprintf(codec->card->longname, sizeof(codec->card->longname), "%s (%s)", machine->name, codec->name); ret = snd_card_register(codec->card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", codec->name); goto out; }#ifdef CONFIG_SND_SOC_AC97_BUS if (ac97) { ret = soc_ac97_dev_register(codec); if (ret < 0) { printk(KERN_ERR "asoc: AC97 device register failed\n"); snd_card_free(codec->card); goto out; } }#endif err = snd_soc_dapm_sys_add(socdev->dev); if (err < 0) printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); err = device_create_file(socdev->dev, &dev_attr_codec_reg); if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");out: mutex_unlock(&codec->mutex); return ret;}EXPORT_SYMBOL_GPL(snd_soc_register_card);/** * snd_soc_free_pcms - free sound card and pcms * @socdev: the SoC audio device * * Frees sound card and pcms associated with the socdev. * Also unregister the codec if it is an AC97 device. */void snd_soc_free_pcms(struct snd_soc_device *socdev){ struct snd_soc_codec *codec = socdev->codec;#ifdef CONFIG_SND_SOC_AC97_BUS struct snd_soc_codec_dai *codec_dai; int i;#endif mutex_lock(&codec->mutex);#ifdef CONFIG_SND_SOC_AC97_BUS for(i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { soc_ac97_dev_unregister(codec); goto free_card; } }free_card:#endif if (codec->card) snd_card_free(codec->card); device_remove_file(socdev->dev, &dev_attr_codec_reg); mutex_unlock(&codec->mutex);}EXPORT_SYMBOL_GPL(snd_soc_free_pcms);/** * snd_soc_set_runtime_hwparams - set the runtime hardware parameters * @substream: the pcm substream * @hw: the hardware parameters * * Sets the substream runtime hardware parameters. */int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw){ struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw.info = hw->info; runtime->hw.formats = hw->formats; runtime->hw.period_bytes_min = hw->period_bytes_min; runtime->hw.period_bytes_max = hw->period_bytes_max; runtime->hw.periods_min = hw->periods_min; runtime->hw.periods_max = hw->periods_max; runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; runtime->hw.fifo_size = hw->fifo_size; return 0;}EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);/** * snd_soc_cnew - create new control * @_template: control template * @data: control private data * @lnng_name: control long name * * Create a new mixer control from a template control. * * Returns 0 for success, else error. */struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, void *data, char *long_name){ struct snd_kcontrol_new template; memcpy(&template, _template, sizeof(template)); if (long_name) template.name = long_name; template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; template.index = 0; return snd_ctl_new1(&template, data);}EXPORT_SYMBOL_GPL(snd_soc_cnew);/** * snd_soc_info_enum_double - enumerated double mixer info callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to provide information about a double enumerated * mixer control. * * Returns 0 for success. */int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = e->shift_l == e->shift_r ? 1 : 2; uinfo->value.enumerated.items = e->mask; if (uinfo->value.enumerated.item > e->mask - 1) uinfo->value.enumerated.item = e->mask - 1; strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]); return 0;}EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);/** * snd_soc_get_enum_double - enumerated double mixer get callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to get the value of a double enumerated mixer. * * Returns 0 for success. */int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val, bitmask; for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; val = snd_soc_read(codec, e->reg); ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); if (e->shift_l != e->shift_r) ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); return 0;}EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);/** * snd_soc_put_enum_double - enumerated double mixer put callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to set the value of a double enumerated mixer. * * Returns 0 for success. */int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val; unsigned short mask, bitmask; for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << e->shift_l; mask = (bitmask - 1) << e->shift_l; if (e->shift_l != e->shift_r) { if (ucontrol->value.enumerated.item[1] > e->mask - 1) return -EINVAL; val |= ucontrol->value.enumerated.item[1] << e->shift_r; mask |= (bitmask - 1) << e->shift_r; } return snd_soc_update_bits(codec, e->reg, mask, val);}EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);/** * snd_soc_info_enum_ext - external enumerated single mixer info callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to provide information about an external enumerated * single mixer. * * Returns 0 for success. */int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = e->mask; if (uinfo->value.enumerated.item > e->mask - 1) uinfo->value.enumerated.item = e->mask - 1; strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]); return 0;}EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);/** * snd_soc_info_volsw_ext - external single mixer info callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to provide information about a single external mixer control. * * Returns 0 for success. */int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ int mask = kcontrol->private_value; 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;}EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);/** * snd_soc_info_volsw - single mixer info callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to provide information about a single mixer control. * * Returns 0 for success. */int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ int mask = (kcontrol->private_value >> 16) & 0xff; int shift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = shift == rshift ? 1 : 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}EXPORT_SYMBOL_GPL(snd_soc_info_volsw);/** * snd_soc_get_volsw - single mixer get callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to get the value of a single mixer control. * * Returns 0 for success. */int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0x01; ucontrol->value.integer.value[0] = (snd_soc_read(codec, reg) >> shift) & mask; if (shift != rshift) ucontrol->value.integer.value[1] = (snd_soc_read(codec, reg) >> rshift) & mask; if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; if (shift != rshift) ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; } return 0;}EXPORT_SYMBOL_GPL(snd_soc_get_volsw);/** * snd_soc_put_volsw - single mixer put callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to set the value of a single mixer control. * * Returns 0 for success. */int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0x01; int err; unsigned short val, val2, val_mask; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; val_mask = mask << shift; val = val << shift; if (shift != rshift) { val2 = (ucontrol->value.integer.value[1] & mask); if (invert) val2 = mask - val2; val_mask |= mask << rshift; val |= val2 << rshift; } err = snd_soc_update_bits(codec, reg, val_mask, val); return err;}EXPORT_SYMBOL_GPL(snd_soc_put_volsw);/** * snd_soc_info_volsw_2r - double mixer info callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to provide information about a double mixer control that * spans 2 codec registers. * * Returns 0 for success. */int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ int mask = (kcontrol->private_value >> 12) & 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;}EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);/** * snd_soc_get_volsw_2r - double mixer get callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to get the value of a double mixer control that spans 2 registers. * * Returns 0 for success. */int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int reg2 = (kcontrol->private_value >> 24) & 0xff; int shift = (kcontrol->private_value >> 8) & 0x0f; int mask = (kcontrol->private_value >> 12) & 0xff; int invert = (kcontrol->private_value >> 20) & 0x01; ucontrol->value.integer.value[0] = (snd_soc_read(codec, reg) >> shift) & mask; ucontrol->value.integer.value[1] = (snd_soc_read(codec, reg2) >> shift) & mask; 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;}EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);/** * snd_soc_put_volsw_2r - double mixer set callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to set the value of a double mixer control that spans 2 registers. * * Returns 0 for success. */int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int reg2 = (kcontrol->private_value >> 24) & 0xff; int shift = (kcontrol->private_value >> 8) & 0x0f; int mask = (kcontrol->private_value >> 12) & 0xff; int invert = (kcontrol->private_value >> 20) & 0x01; int err; unsigned short val, val2, val_mask; val_mask = mask << shift; val = (ucontrol->value.integer.value[0] & mask); val2 = (ucontrol->value.integer.value[1] & mask); if (invert) { val = mask - val; val2 = mask - val2; } val = val << shift; val2 = val2 << shift; if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) return err; err = snd_soc_update_bits(codec, reg2, val_mask, val2); return err;}EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);static int __devinit snd_soc_init(void){ printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); return platform_driver_register(&soc_driver);}static void snd_soc_exit(void){ platform_driver_unregister(&soc_driver);}module_init(snd_soc_init);module_exit(snd_soc_exit);/* Module information */MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");MODULE_DESCRIPTION("ALSA SoC Core");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -