📄 soc-dapm.c
字号:
wsink->id == snd_soc_dapm_line || wsink->id == snd_soc_dapm_output) wsink->ext = 1; } if (wsource->id == snd_soc_dapm_output) { if (wsink->id == snd_soc_dapm_spk || wsink->id == snd_soc_dapm_hp || wsink->id == snd_soc_dapm_line || wsink->id == snd_soc_dapm_input) wsource->ext = 1; } /* connect static paths */ if (control == NULL) { list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 1; return 0; } /* connect dynamic paths */ switch(wsink->id) { case snd_soc_dapm_adc: case snd_soc_dapm_dac: case snd_soc_dapm_pga: case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 1; return 0; case snd_soc_dapm_mux: ret = dapm_connect_mux(codec, wsource, wsink, path, control, &wsink->kcontrols[0]); if (ret != 0) goto err; break; case snd_soc_dapm_switch: case snd_soc_dapm_mixer: ret = dapm_connect_mixer(codec, wsource, wsink, path, control); if (ret != 0) goto err; break; case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: case snd_soc_dapm_spk: list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 0; return 0; } return 0;err: printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source, control, sink); kfree(path); return ret;}EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);/** * snd_soc_dapm_new_widgets - add new dapm widgets * @codec: audio codec * * Checks the codec for any new dapm widgets and creates them if found. * * Returns 0 for success. */int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec){ struct snd_soc_dapm_widget *w; mutex_lock(&codec->mutex); list_for_each_entry(w, &codec->dapm_widgets, list) { if (w->new) continue; switch(w->id) { case snd_soc_dapm_switch: case snd_soc_dapm_mixer: dapm_new_mixer(codec, w); break; case snd_soc_dapm_mux: dapm_new_mux(codec, w); break; case snd_soc_dapm_adc: case snd_soc_dapm_dac: case snd_soc_dapm_pga: dapm_new_pga(codec, w); break; case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: case snd_soc_dapm_spk: case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: break; } w->new = 1; } dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); mutex_unlock(&codec->mutex); return 0;}EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);/** * snd_soc_dapm_get_volsw - dapm mixer get callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to get the value of a dapm mixer control. * * Returns 0 for success. */int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_dapm_widget *widget = 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; /* return the saved value if we are powered down */ if (widget->id == snd_soc_dapm_pga && !widget->power) { ucontrol->value.integer.value[0] = widget->saved_value; return 0; } ucontrol->value.integer.value[0] = (snd_soc_read(widget->codec, reg) >> shift) & mask; if (shift != rshift) ucontrol->value.integer.value[1] = (snd_soc_read(widget->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_dapm_get_volsw);/** * snd_soc_dapm_put_volsw - dapm mixer set callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to set the value of a dapm mixer control. * * Returns 0 for success. */int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_dapm_widget *widget = 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; unsigned short val, val2, val_mask; int ret; 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; } mutex_lock(&widget->codec->mutex); widget->value = val; /* save volume value if the widget is powered down */ if (widget->id == snd_soc_dapm_pga && !widget->power) { widget->saved_value = val; mutex_unlock(&widget->codec->mutex); return 1; } dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); if (ret < 0) goto out; } ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); if (widget->event_flags & SND_SOC_DAPM_POST_REG) ret = widget->event(widget, SND_SOC_DAPM_POST_REG); } else ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);out: mutex_unlock(&widget->codec->mutex); return ret;}EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);/** * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to get the value of a dapm enumerated double mixer control. * * Returns 0 for success. */int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_dapm_widget *widget = 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(widget->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_dapm_get_enum_double);/** * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback * @kcontrol: mixer control * @uinfo: control element information * * Callback to set the value of a dapm enumerated double mixer control. * * Returns 0 for success. */int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val, mux; unsigned short mask, bitmask; int ret = 0; for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; mux = ucontrol->value.enumerated.item[0]; val = mux << 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; } mutex_lock(&widget->codec->mutex); widget->value = val; dapm_mux_update_power(widget, kcontrol, mask, mux, e); if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); if (ret < 0) goto out; } ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); if (widget->event_flags & SND_SOC_DAPM_POST_REG) ret = widget->event(widget, SND_SOC_DAPM_POST_REG); } else ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);out: mutex_unlock(&widget->codec->mutex); return ret;}EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);/** * snd_soc_dapm_new_control - create new dapm control * @codec: audio codec * @widget: widget template * * Creates a new dapm control based upon the template. * * Returns 0 for success else error. */int snd_soc_dapm_new_control(struct snd_soc_codec *codec, const struct snd_soc_dapm_widget *widget){ struct snd_soc_dapm_widget *w; if ((w = dapm_cnew_widget(widget)) == NULL) return -ENOMEM; w->codec = codec; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); list_add(&w->list, &codec->dapm_widgets); /* machine layer set ups unconnected pins and insertions */ w->connected = 1; return 0;}EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);/** * snd_soc_dapm_stream_event - send a stream event to the dapm core * @codec: audio codec * @stream: stream name * @event: stream event * * Sends a stream event to the dapm core. The core then makes any * necessary widget power changes. * * Returns 0 for success else error. */int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, int event){ struct snd_soc_dapm_widget *w; if (stream == NULL) return 0; mutex_lock(&codec->mutex); list_for_each_entry(w, &codec->dapm_widgets, list) { if (!w->sname) continue; dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, stream, event); if (strstr(w->sname, stream)) { switch(event) { case SND_SOC_DAPM_STREAM_START: w->active = 1; break; case SND_SOC_DAPM_STREAM_STOP: w->active = 0; break; case SND_SOC_DAPM_STREAM_SUSPEND: if (w->active) w->suspend = 1; w->active = 0; break; case SND_SOC_DAPM_STREAM_RESUME: if (w->suspend) { w->active = 1; w->suspend = 0; } break; case SND_SOC_DAPM_STREAM_PAUSE_PUSH: break; case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: break; } } } mutex_unlock(&codec->mutex); dapm_power_widgets(codec, event); dump_dapm(codec, __FUNCTION__); return 0;}EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);/** * snd_soc_dapm_set_endpoint - set audio endpoint status * @codec: audio codec * @endpoint: audio signal endpoint (or start point) * @status: point status * * Set audio endpoint status - connected or disconnected. * * Returns 0 for success else error. */int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, char *endpoint, int status){ struct snd_soc_dapm_widget *w; list_for_each_entry(w, &codec->dapm_widgets, list) { if (!strcmp(w->name, endpoint)) { w->connected = status; } } return 0;}EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);/** * snd_soc_dapm_free - free dapm resources * @socdev: SoC device * * Free all dapm widgets and resources. */void snd_soc_dapm_free(struct snd_soc_device *socdev){ struct snd_soc_codec *codec = socdev->codec; snd_soc_dapm_sys_remove(socdev->dev); dapm_free_widgets(codec);}EXPORT_SYMBOL_GPL(snd_soc_dapm_free);/* Module information */MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -