Linux ALSA音频驱动三:DAPM电源管理

3 篇文章 5 订阅
订阅专栏

结合dapm电源管理机制,codec根据自己的能力向ALSA注册自己的kcontrol, widget以及routes,可以实现寄存器通路的选择以及动态开关。

声卡注册成功后可通过amixer或tinymix查看其kcontrol信息,如下所示。

root@ubuntu:/mnt# amixer controls
numid=3,iface=MIXER,name='Master Mono Playback Switch'
numid=4,iface=MIXER,name='Master Mono Playback Volume'
numid=1,iface=MIXER,name='Master Playback Switch'
numid=2,iface=MIXER,name='Master Playback Volume'

DAPM的存在使得无需修改内核代码便可轻易切换CODEC通路,只需在用户态通过触发playback/capture数据流或tinymix配置通路实现。下面摘抄一段经典讲述。

3.1、audio paths overview

本节来自CSDN: DAPM之二:audio paths与dapm kcontrol_sepnic的博客-CSDN博客

先看图3.1,红色线路是LINPUT1(Left Input) -> LEFT INPUT PGA -> LEFT INPUT MIXER -> LEFT OUTPUT MIXER -> LINEOUT1L,表示从LINPUT输入的信号通过这条路径送到LINEOUT输出,再具现一点,就是录音信号直接放到SPK播出。在这条路径上,有三个带+号的圆圈,那就是多路混合器mixer,用于切换输入源或将多个输入源混合输出。

土黄色部分为LEFT INPUT PGA:可选择LINPUT1、LINPUT2和LINPUT3;

绿色部分是LEFT INPUT MIXER:可选择INPUTPGA、LINPUT2、LINPUT3和AUX/LCOM;

蓝色部分是LEFT OUTPUT MIXER:可选择INPUTMIXER、LINPUT3、AUX/LCOM和LEFT DAC等。

 图3.1 声卡原理图

配置声音通路时,主要是对mixer做切换输入源操作。如要实现Playback,则需要打通DAC -> OUTPUT MIXER -> LINEOUT通路。

可将图3.1抽象成图3.2。

图3.2 CODEC通路抽象图

上图一共有3条通路,即:

  1. 录音通路:Mic -> Input Mixer -> ADC
  2. 录播通路:Mic -> Input Mixer -> Output Mixer -> HP/SPK
  3. 播放通路:DAC -> Output Mixer -> HP/SPK

上面涉及到了DAPM通路的概念,其中涉及到很多音频驱动术语,如mixer, mux, path等,下面作进一步分析。

3.2、kcontrol定义

Kcontrol代表声卡里的各种硬件开关,滑动控件等,通过软件定义kcontrol可通过用户态配置硬件寄存器的开和关。

ALSA用snd_kcontrol_new定义kcontrol。

struct snd_kcontrol_new {
    snd_ctl_elem_iface_t iface; /* interface identifier */
    unsigned int device;        /* device/client number */
    unsigned int subdevice;     /* subdevice (substream) number */
    const char *name;       /* ASCII name of item */
    unsigned int index;     /* index of item */
    unsigned int access;        /* access rights */
    unsigned int count;     /* count of same elements */
    snd_kcontrol_info_t *info;
    snd_kcontrol_get_t *get;
    snd_kcontrol_put_t *put;
    union {
        snd_kcontrol_tlv_rw_t *c;
        const unsigned int *p;
    } tlv;
    unsigned long private_value;
};

name: 表示该kcontrol的名字。

info:回调函数,用于获取control的详细信息。

get:回调函数,用于读取control的当前值。

put:回调函数,用于把应用程序的控制值设置到control中。

ALSA提供了一整套宏用于定义kcontrol控件,其中一类是通路中的某一条路径,通常是mixer的一路分支,用SOC_DAPM_XXX定义,另一类是零散的不影响通路状态,用SOC_SINGLE_XXX定义。

Dapm控件由soc-dapm.h中的一组宏来定义,如SOC_DAPM_SINGLE等。

#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
{   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
    .info = snd_soc_info_volsw, \
    .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
    .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
非dapm控件通常由include\sound\soc.h中的宏来定义,如SOC_SINGLE.
#define SOC_SINGLE(xname, reg, shift, max, invert) \
{   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
    .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
    .put = snd_soc_put_volsw, \
    .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }

对比发现dapm与非dapm定义大体类似,都由SOC_SINGLE_VALUE定义基本信息,reg, shift, max, invert等,而区别主要在get, put回调。

dapm控件的get, put回调会触发相邻控件加入dirty链表,继而触发整条路径的搜索,而非dapm控件仅仅是触发自身的读写,不具备传导作用。

int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_value *ucontrol)
{
    struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
    struct snd_soc_card *card = dapm->card;
    struct soc_mixer_control *mc =
        (struct soc_mixer_control *)kcontrol->private_value;
    int reg = mc->reg;
    unsigned int shift = mc->shift;
    int max = mc->max;
    unsigned int width = fls(max);
    unsigned int mask = (1 << width) - 1;
    unsigned int invert = mc->invert;
    unsigned int val, rval = 0;
    int connect, rconnect = -1, change, reg_change = 0;
    struct snd_soc_dapm_update update = {};
    int ret = 0;

    val = (ucontrol->value.integer.value[0] & mask);
    connect = !!val;

    if (invert)
        val = max - val;

    if (snd_soc_volsw_is_stereo(mc)) {
        rval = (ucontrol->value.integer.value[1] & mask);
        rconnect = !!rval;
        if (invert)
            rval = max - rval;
    }

    mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);

    /* This assumes field width < (bits in unsigned int / 2) */
    if (width > sizeof(unsigned int) * 8 / 2)
        dev_warn(dapm->dev,
             "ASoC: control %s field width limit exceeded\n",
             kcontrol->id.name);
    change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));

    if (reg != SND_SOC_NOPM) {
        val = val << shift;
        rval = rval << mc->rshift;

        reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);

        if (snd_soc_volsw_is_stereo(mc))
            reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
                             mask << mc->rshift,
                             rval);
    }

    if (change || reg_change) {
        if (reg_change) {
            if (snd_soc_volsw_is_stereo(mc)) {
                update.has_second_set = true;
                update.reg2 = mc->rreg;
                update.mask2 = mask << mc->rshift;
                update.val2 = rval;
            }
            update.kcontrol = kcontrol;
            update.reg = reg;
            update.mask = mask << shift;
            update.val = val;
            card->update = &update;
        }
        change |= reg_change;

        ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
                          rconnect);

        card->update = NULL;
    }

    mutex_unlock(&card->dapm_mutex);

    if (ret > 0)
        snd_soc_dpcm_runtime_update(card);

    return change;
}

Kcontrol的基本信息都存在private_value中,如果待写入值与当前值的差异,会触发soc_dapm_mixer_update_power更新kcontrol。

static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
                       struct snd_kcontrol *kcontrol,
                       int connect, int rconnect)
{
    struct snd_soc_dapm_path *path;
    int found = 0;

    lockdep_assert_held(&card->dapm_mutex);

    /* find dapm widget path assoc with kcontrol */
    dapm_kcontrol_for_each_path(path, kcontrol) {
        if (found && rconnect >= 0)
            soc_dapm_connect_path(path, rconnect, "mixer update");
        else
            soc_dapm_connect_path(path, connect, "mixer update");
        found = 1;
    }

    if (found)
        dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);

    return found;
}

dapm_power_widgets具体状态传导作用,会将当前kcontrol相邻的kcontrol都加入dirty链表,后面会分析。

3.3、widget定义

DAPM通路切换是通过配置不同的route表来实现的,影响音频route开关的组件称为widget,下面看看widget类型。

/* dapm widget types */
enum snd_soc_dapm_type {
    snd_soc_dapm_input = 0,     /* input pin */
    snd_soc_dapm_output,        /* output pin */
    snd_soc_dapm_mux,           /* selects 1 analog signal from many inputs */
    snd_soc_dapm_demux,         /* connects the input to one of multiple outputs */
    snd_soc_dapm_mixer,         /* mixes several analog signals together */
    snd_soc_dapm_mixer_named_ctl,       /* mixer with named controls */
    snd_soc_dapm_pga,           /* programmable gain/attenuation (volume) */
    snd_soc_dapm_out_drv,           /* output driver */
    snd_soc_dapm_adc,           /* analog to digital converter */
    snd_soc_dapm_dac,           /* digital to analog converter */
    snd_soc_dapm_micbias,       /* microphone bias (power) - DEPRECATED: use snd_soc_dapm_supply */
    snd_soc_dapm_mic,           /* microphone */
    snd_soc_dapm_hp,            /* headphones */
    snd_soc_dapm_spk,           /* speaker */
    snd_soc_dapm_line,          /* line input/output */
    snd_soc_dapm_switch,        /* analog switch */
    snd_soc_dapm_vmid,          /* codec bias/vmid - to minimise pops */
    snd_soc_dapm_pre,           /* machine specific pre widget - exec first */
    snd_soc_dapm_post,          /* machine specific post widget - exec last */
    snd_soc_dapm_supply,        /* power/clock supply */
    snd_soc_dapm_pinctrl,       /* pinctrl */
    snd_soc_dapm_regulator_supply,  /* external regulator */
    snd_soc_dapm_clock_supply,  /* external clock */
    snd_soc_dapm_aif_in,        /* audio interface input */
    snd_soc_dapm_aif_out,       /* audio interface output */
    snd_soc_dapm_siggen,        /* signal generator */
    snd_soc_dapm_sink,
    snd_soc_dapm_dai_in,        /* link to DAI structure */
    snd_soc_dapm_dai_out,
    snd_soc_dapm_dai_link,      /* link between two DAI structures */
    snd_soc_dapm_kcontrol,      /* Auto-disabled kcontrol */
    snd_soc_dapm_buffer,        /* DSP/CODEC internal buffer */
    snd_soc_dapm_scheduler,     /* DSP/CODEC internal scheduler */
    snd_soc_dapm_effect,        /* DSP/CODEC effect component */
    snd_soc_dapm_src,       /* DSP/CODEC SRC component */
    snd_soc_dapm_asrc,      /* DSP/CODEC ASRC component */
    snd_soc_dapm_encoder,       /* FW/SW audio encoder component */
    snd_soc_dapm_decoder,       /* FW/SW audio decoder component */

    /* Don't edit below this line */
    SND_SOC_DAPM_TYPE_COUNT
};

影响path通路最常用的几种widget,如mixer, mux, switch等。

MIXER:多个输入源混合成一个输出,用SND_SOC_DAPM_MIXER定义这个widget,类型为snd_soc_dapm_mixer;

MUX:多路选择器,多路输入,但只能选择一路作为输出,用SND_SOC_DAPM_MUX定义这个widget,类型为snd_soc_dapm_mux;

PGA:单路输入,单路输出,带gain调整的部件,用SND_SOC_DAPM_PGA定义这个widget,类型为snd_soc_dapm_pga。

下面分别看看如何定义。

3.3.1、Mixer定义

Mixer意在将多个输入混合成一个输出,如手机同时打电话,又播放音乐,需要将两路数据混合后再输出到speaker,就需要用到mixer,如图3.3所示。

图3.3 mixer原理图

Mixer驱动定义分几个步骤,如下所述。

1、定义输入源选择

/* Speaker Mixer */
static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = {
SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 11, 1, 1),
SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1),
SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1),
SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1),
SOC_DAPM_SINGLE("MonoIn Playback Switch", AC97_MASTER_TONE, 14, 1, 1),
SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1),
};

2、定义mixer

static const struct snd_soc_dapm_widget wm9713_dapm_widgets[] = {
……
SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1,
    &wm9713_speaker_mixer_controls[0],
    ARRAY_SIZE(wm9713_speaker_mixer_controls)),
……
};

3.3.2、mux定义

Mux控件也是多路输入,单路输出的结构,但与mixer不同的是,每次只能选择一路作为输出,相当于是单选输出。

图3.4 mux原理图

Mux驱动定义分如下几步。

1、定义输入源

static const char *wm9713_spk_pga[] =
    {"Vmid", "Zh", "Headphone", "Speaker", "Inv", "Headphone Vmid",
    "Speaker Vmid", "Inv Vmid"};
static const struct soc_enum wm9713_enum[] = {
……
SOC_ENUM_SINGLE(AC97_REC_GAIN, 8, 8, wm9713_spk_pga), /* speaker right input select 9 */
……
};

/* speaker right output mux */
static const struct snd_kcontrol_new wm9713_hp_spkr_mux_controls =
SOC_DAPM_ENUM("Route", wm9713_enum[9]);

2、定义mux控件

SND_SOC_DAPM_MUX("Right Speaker Out Mux", SND_SOC_NOPM, 0, 0,
    &wm9713_hp_spkr_mux_controls),

3.3.3、DAC/ADC定义

有一类widget需要和stream widget连接,而且不需要在驱动里添加route连接,因为ALSA会自动为其建立连接。这类widget包括DAC/ADC,AIF IN / AIF OUT等。

SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_EXTENDED_MID, 7, 1),
SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_EXTENDED_MID, 6, 1),
SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),

这类widget除了wname外还有sname字段需要填充,sname用来和stream widget建立匹配用的,如上面代码里的"Left HiFi Playback"等。

#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{   .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
    SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }

声卡驱动在初始化的时候就会为每个dai创建dai widget,而widget的名字就是stream name。

static int soc_probe_component(struct snd_soc_card *card,
                   struct snd_soc_component *component)
{
……
    for_each_component_dais(component, dai) {
        ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
        if (ret != 0) {
            dev_err(component->dev,
                "Failed to create DAI widgets %d\n", ret);
            goto err_probe;
        }
    }
……
}

具体创建工作是在snd_soc_dapm_new_dai_widgets里完成的。

int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                 struct snd_soc_dai *dai)
{
    struct snd_soc_dapm_widget template;
    struct snd_soc_dapm_widget *w;

    WARN_ON(dapm->dev != dai->dev);

    memset(&template, 0, sizeof(template));
    template.reg = SND_SOC_NOPM;

    if (dai->driver->playback.stream_name) {
        template.id = snd_soc_dapm_dai_in;
        template.name = dai->driver->playback.stream_name;
        template.sname = dai->driver->playback.stream_name;

        dev_dbg(dai->dev, "ASoC: adding %s widget\n",
            template.name);

        w = snd_soc_dapm_new_control_unlocked(dapm, &template);
        if (IS_ERR(w))
            return PTR_ERR(w);

        w->priv = dai;
        dai->playback_widget = w;
    }

    if (dai->driver->capture.stream_name) {
        template.id = snd_soc_dapm_dai_out;
        template.name = dai->driver->capture.stream_name;
        template.sname = dai->driver->capture.stream_name;

        dev_dbg(dai->dev, "ASoC: adding %s widget\n",
            template.name);

        w = snd_soc_dapm_new_control_unlocked(dapm, &template);
        if (IS_ERR(w))
            return PTR_ERR(w);

        w->priv = dai;
        dai->capture_widget = w;
    }

    return 0;
}

而建立连接是在snd_soc_dapm_link_dai_widgets里完成的。

int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
{
    struct snd_soc_dapm_widget *dai_w, *w;
    struct snd_soc_dapm_widget *src, *sink;
    struct snd_soc_dai *dai;

    /* For each DAI widget... */
    for_each_card_widgets(card, dai_w) {
        switch (dai_w->id) {
        case snd_soc_dapm_dai_in:
        case snd_soc_dapm_dai_out:
            break;
        default:
            continue;
        }

        /* let users know there is no DAI to link */
        if (!dai_w->priv) {
            dev_dbg(card->dev, "dai widget %s has no DAI\n",
                dai_w->name);
            continue;
        }

        dai = dai_w->priv;

        /* ...find all widgets with the same stream and link them */
        for_each_card_widgets(card, w) {
            if (w->dapm != dai_w->dapm)
                continue;

            switch (w->id) {
            case snd_soc_dapm_dai_in:
            case snd_soc_dapm_dai_out:
                continue;
            default:
                break;
            }

            if (!w->sname || !strstr(w->sname, dai_w->sname))
                continue;

            if (dai_w->id == snd_soc_dapm_dai_in) {
                src = dai_w;
                sink = w;
            } else {
                src = w;
                sink = dai_w;
            }
            dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
            snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
        }
    }

    return 0;
}

看上面只有w->sname包括dai_w->sname才会连接成功,因此只有DAC/ADC, AIF IN / AIF OUT才能和dai in / dai out建立连接。

连接成功后能感知音频事件,

static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
    int event)
{
    struct snd_soc_dapm_widget *w;
    unsigned int ep;

    w = snd_soc_dai_get_widget(dai, stream);

    if (w) {
        dapm_mark_dirty(w, "stream event");

        if (w->id == snd_soc_dapm_dai_in) {
            ep = SND_SOC_DAPM_EP_SOURCE;
            dapm_widget_invalidate_input_paths(w);
        } else {
            ep = SND_SOC_DAPM_EP_SINK;
            dapm_widget_invalidate_output_paths(w);
        }

        switch (event) {
        case SND_SOC_DAPM_STREAM_START:
            w->active = 1;
            w->is_ep = ep;
            break;
        case SND_SOC_DAPM_STREAM_STOP:
            w->active = 0;
            w->is_ep = 0;
            break;
        case SND_SOC_DAPM_STREAM_SUSPEND:
        case SND_SOC_DAPM_STREAM_RESUME:
        case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
        case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
            break;
        }
    }
}

起播时的触发流程。

soc_pcm_prepare
    snd_soc_dapm_stream_event(SND_SOC_DAPM_STREAM_START)
        soc_dapm_stream_event
            soc_dapm_dai_stream_event
            dapm_power_widgets

结束时的触发流程。

soc_pcm_close
    soc_pcm_clean
        snd_soc_dapm_stream_stop
            snd_soc_dapm_stream_event(SND_SOC_DAPM_STREAM_STOP)
                soc_dapm_stream_event
                    soc_dapm_dai_stream_event
                    dapm_power_widgets

3.4、route定义

定义了mixer, mux及其它widget后需要定义route结构将它们连接起来,否则ALSA并不知道这些控件是如何连接的。Route结构体定义如下。

struct snd_soc_dapm_route {
    const char *sink;
    const char *control;
    const char *source;

    /* Note: currently only supported for links where source is a supply */
    int (*connected)(struct snd_soc_dapm_widget *source,
             struct snd_soc_dapm_widget *sink);

    struct snd_soc_dobj dobj;
};

Sink,source是要连接的控件名字,control是连接开关的名字,一条完整的route如图3.5所示。

图3.5 一条完整的端到端输出

对应的route定义如下。

static const struct snd_soc_dapm_route wm9713_audio_map[] = {
    {"Speaker Mixer", "Aux Playback Switch",     "Aux DAC"},
……
    {"Right Speaker Out Mux", "Speaker", "Speaker Mixer"},
……
    {"Right Speaker", NULL, "Right Speaker Out Mux"},
    {"SPKR", NULL, "Right Speaker"},
};

Linux Alsa声卡驱动(1):简介
qq_34968572的博客
07-14 1293
往日工作中对于声卡驱动的调试也仅仅局限于编译供应商提供的codec及配置dts,并没有去深入了解声卡驱动,目前打算去好好研究一下,为了以后能更好的处理关于声卡驱动方面的问题。经过网上查阅资料发现好多文章都是基于早前的内核版本,API以及结构已经变动了好多。目前我工作主要是基于RK的芯片做项目,内核版本为4.19.111,就基于该版本内核做一下详细分析。 该专栏将记录我的声卡驱动学习经历,由于工作原因更新时间可能不确定,内容可能也会有些许出入,但后续会慢慢完善。 ALSA(The
08.音频系统:第003课_Linux音频驱动程序:第008节_DAPM的情景分析_使用过程
江南才尽江南山,年少无知年少狂!
04-19 1242
该小节我们讲解DAPM的情景分析的构造过程,我们先回顾一下widget上电的过程,如下是一条上电路线: 从LINPUT1经过两个Mixer到达ADC,从图上可以看出,控制接口共六个部分,只要其中有一个部分没有打开(connect),则该线路的所有开关都不会打开。如果其上所有接口都开看,并且有应用程序使用这个声卡,那么图中的四个widget全部都会打开。这样就是comlete path,即满足3个......
ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)
DroidPhone的专栏
11-09 2万+
前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等。本章我们准备讨论dapm框架中的另一个机制:事件机制。通过dapm事件机制,widget可以对它所关心的dapm事件做出反应,这种机制对于扩充widget的能力非常有用,例如,对于那些位于codec之外的widget,好像喇叭功放、外部的前置放大
Linux alsa音频框架DAPM介绍
最新发布
u014231040的博客
07-17 279
DAPM(Dynamic Audio Power Management,动态音频电源管理)是ALSA系统中的一个关键组件,主要负责在音频播放和录制过程中动态控制音频部件的电源状态,以实现节能。DAPM分为多个组件,每个组件代表音频传输路径中的一个节点,例如麦克风、放大器、DAC(数模转换器)、ADC(模数转换器)等。总结来说,DAPM是一个功能强大且复杂的组件,通过动态管理音频路径和节点的电源状态,显著降低了系统的整体功耗,对于在ALSA框架下开发音频应用的开发者来说非常重要。节点之间通过路径连接。
ALSA DAPM
aningxiaoxixi的博客
09-01 209
kcontrol 介绍 kcontrol 结构中包含 一个或多个寄存器值,表示一个功能 ** kcontrol结构 ** 1 snd_kcontrol 结构体 表示 kcontrol 2 snd_kcontrol 结构体 放入 snd_card的 controls 的链表中
ALSA声卡驱动中的DAPM详解之:如何定义各种widget
热门推荐
DroidPhone的专栏
10-24 3万+
/*****************************************************************************************************/ 声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢! /**************************************
ALSA声卡驱动中的DAPM详解
yangguoyu8023的博客
05-12 1078
ALSA声卡驱动中的DAPM详解
Alsa里面恶心的DAPM
嵌入式Linux
09-07 2320
相关文章音频系统,Alsa 里面的buff 是怎么计算的?为什么需要超过48k的采样音频?我在MTK平台下调试音频ALSA音频几个重要的参数openwrt 音频开发(干货)Ai音箱和Li...
基于TCC8801的嵌入式Linux ALSA音频驱动设计与研究.pdf
09-06
"基于TCC8801的嵌入式Linux ALSA音频驱动设计与研究" 本文主要介绍了基于TCC8801的嵌入式Linux ALSA音频驱动设计与研究。 ALSA(Advanced Linux Sound Architecture)音频系统框架已经成为Linux内核中的主流音频...
Linux Alsa音频驱动框架(声卡的运行以及PCM数据流读写)
EmLinuxDeveloper的博客
06-08 1005
alsa lib层会有snd_pcm_hw_params_set_period_size_near和snd_pcm_hw_params_set_buffer_size_near,之所有是near,是因为这两个接口都是设置接近值,如果硬件不支持设定的值,会设置硬件能提供的接近值,如果硬件层buffer_bytes_max和period_bytes_max设置很小,那么上层如果设置很大,那么上层设置就不会成功,最大只能是硬件的设定值;
ALSA声卡驱动中的DAPM详解之二:widget-具备路径和电源管理信息的kcontrol
sinat_37817094的博客
11-27 837
上一篇文章中,我们介绍了音频驱动中对基本控制单元的封装:kcontrol。利用kcontrol,我们可以完成对音频系统中的mixer,mux,音量控制,音效控制,以及各种开关量的控制,通过对各种kcontrol的控制,使得音频硬件能够按照我们预想的结果进行工作。同时我们可以看到,kcontrol还是有以下几点不足: (1)只能描述自身,无法描述各个kcontrol之间的连接关系; (2)没有相应...
ALSA声卡驱动DAPM
aningxiaoxixi的博客
06-27 859
参考文章 ALSA声卡驱动DAPM DAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASoc core中完成。用户空间的应用程序无需对代码做出修改,也无需重新编译,DAPM根据当前激活的音频流(playback/capture)和声卡中的mixer等的配置来决定那些音频控件的电源开关被
alsadapm笔记
MTzhou的专栏
03-08 1211
参考博客 宗旨 snd_soc_dapm_context snd_soc_dapm_widget DAPM之内部API DAPM之外部API 参考博客 ALSA架构详解 宗旨分析dapm的代码不应以弄清除dapm原理为目标,而应该是出于可以看懂和编写codec或者platform驱动目的。毕竟代码万万,linux kernel已经封装的接口又不需要驱动开发者实现。驱动开发者不应该浪费有限的生命。sn
[Alsa Document]5, dapm.txt
wangyijieonline的博客
03-05 560
仔细读过前几篇 machine.txt codec.txt platform.txt 文档的同学会发现,里面反复出现一个名词——“dapm”,比如: Platform: Codec: 本篇来介绍dapm (Dynamic Audio Power Management, 动态音频电源管理) 基于4.9.123版本内核 Documentation/sound/alsa/soc/dapm.tx...
Linux内核4.14版本——alsa框架分析(19)——DAPM(10)——dapm事件机制(dapm event)
yangguoyu8023的博客
07-10 992
前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等。本章我们准备讨论dapm框架中的另一个机制:事件机制。通过dapm事件机制,widget可以对它所关心的dapm事件做出反应,这种机制对于扩充widget的能力非常有用,例如,对于那些位于codec之外的widget,好像喇叭功放、外部的前置放大器等等,由于不是使用codec内部的寄存器进行电源控制,我们就必须利用dapm的事件机制,获得相应的......
Linux内核4.14版本——alsa框架分析(14)——DAPM(5)——注册widget、route、path
yangguoyu8023的博客
07-10 1760
驱动程序中初始化并注册widget和route
Linux ALSA架构:DPAM概念详解(
m0_51231887的博客
08-13 794
Linux ALSA架构:DPAM概念详解() 一、DAPM简介 DAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASOC core中完成。用户空间的应用程序无需对代码做出修改,也无需重新编译,DAPM根据当前激活的音频流(playback/capture)和声卡中的mixer等的配置来
写文章

热门文章

  • Linux ALSA音频驱动二:ALSA驱动注册 3848
  • automake 及 autoconfig, 以及如何用gdb调试[转载] 2169
  • Linux ALSA音频驱动三:DAPM电源管理 1869
  • Mediainfo的编译安装[自己编译过一遍的] 1472
  • Linux ALSA音频驱动一:音频系统概述 937

分类专栏

  • Linux ALSA音频驱动 3篇
  • 转载

最新评论

  • Linux ALSA音频驱动二:ALSA驱动注册

    ♚ 余事勿取✨: tui

  • Linux ALSA音频驱动二:ALSA驱动注册

    李卤蛋: 请问同时注册两个声卡怎么操作

  • Linux ALSA音频驱动二:ALSA驱动注册

    baidu_40709951: 博主写的哈详细,强推

最新文章

  • Linux ALSA音频驱动二:ALSA驱动注册
  • Linux ALSA音频驱动一:音频系统概述
  • automake 及 autoconfig, 以及如何用gdb调试[转载]
2022年3篇
2013年2篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家玻璃钢迎宾公仔雕塑520商场美陈装修山东水果玻璃钢雕塑定做价格宣城玻璃钢雕塑价位玻璃钢欧式雕塑公司成都玻璃钢雕塑定制商场美陈全年布置方案云南玻璃钢卡通雕塑价格杭州商场美陈销售厂家台州玻璃钢陶瓷雕塑设计温江玻璃钢花盆花器昌乐玻璃钢花盆花器贵安新区玻璃钢雕塑厂有哪些青岛人物玻璃钢雕塑价格玻璃钢花盆底座合肥校园玻璃钢雕塑生产厂家玻璃钢雕塑的照片附近校园玻璃钢雕塑厂景观玻璃钢雕塑制作设计厂家四川玻璃钢商场美陈雕塑定制玻璃钢雕塑便宜山东户外商场美陈供应商西红柿玻璃钢雕塑价格校园玻璃钢雕塑制作多少钱聊城玻璃钢长颈雕塑泰州商场入口美陈花朵玻璃钢卡通雕塑定做房山区商场美陈合肥玻璃钢天壶雕塑英德室内外玻璃钢花盆哪家好香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化