ALSA sound card driver dapm in one of the detailed: Kcontrol

Source: Internet
Author: User

DAPM is the acronym for Dynamic Audio Power management, which means that the audio subsystem on a Linux based mobile device is designed to work in a minimum power state at all times. DAPM is transparent to user-space applications, and all power-related switches are done in ASOC core. User-space Applications do not need to modify the code, and do not need to recompile, DAPM the power switch of the audio control is turned on or off, depending on the configuration of the current active audio stream (playback/capture) and the mixer in the sound card.

/*****************************************************************************************************/
Statement: This Bo content by Http://blog.csdn.net/droidphone Original, reproduced please indicate the source, thank you.
/*****************************************************************************************************/

The DAPM control is evolved from an ordinary SOC audio control, so the content of this chapter begins with the Common Soc audio control. snd_kcontrol_new Structure

Before we formally discuss DAPM, we need to understand one important concept in ASOC: Kcontrol, unfamiliar readers need to browse through my previous article: Linux ALSA sound card driver Four: control device creation. Typically, a kcontrol represents a mixer (mixer), or a MUX (multi-channel switch), or a volume controller, and so on. As we know from the above article, defining a kcontrol is primarily about defining a snd_kcontrol_new structure, which, for the sake of discussion, is again given its definition:[CPP] View Plain Copy 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 unsigned 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;  };  

Back to Linux ALSA sound card driver Four: Control device creation, we know that for each of the controls, we need to define a and his corresponding snd_kcontrol_new structure, these snd_kcontrol_new structure in the sound card initialization phase, Registered to the system through the Snd_soc_add_codec_controls function, user space can view and set the state of these controls through tools such as Amixer or alsamixer. In the snd_kcontrol_new structure, several primary fields are the Get,put,private_value,get callback function to get the current state value of the control, while the put callback function sets the control's state value, while the Private_ The value field has different meanings depending on the control type, for example, for ordinary controls, the Private_value field can be used to define the address of the register corresponding to the control and the position information of the corresponding control bit in the register. Thankfully, the ASOC system has prepared a number of macro definitions for us to define commonly used controls, which are located in Include/sound/soc.h. Let's discuss how to use these preset macro definitions to define some of the commonly used controls. Simple type of control

Soc_singleSoc_single should be the simplest control, with only one control, such as a switch, or a numeric variable (such as a frequency in codec, FIFO size, and so on). Let's take a look at how this macro is defined:[CPP]View Plain copy #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)} macro-defined parameters are: XName (the name of the control), Reg (the address of the corresponding register for the control), shift (control bit in register , Max (the maximum value the control can set), invert (the set value is logically reversed). Here again, a macro is used to define the Private_value field: Soc_single_value, let's look at its definition:[CPP] View Plain copy #define &NBSP;SOC_DOUBLE_VALUE (Xreg, shift_left, shift_right, xmax, xinvert)  \            ((Unsigned long) & (STRUCT&NBSP;SOC_ Mixer_control)  \           {.reg = xreg,  .rreg = xreg, .shift = shift_left, \            .rshift = shift_right, .max = xmax, .platform_max =  xmax, \           .invert = xinvert})     #define &NBSP;SOC_SINGLE_VALUE (Xreg, xshift, xmax, xinvert)  \            soc_double_value (Xreg, xshift, xshift, xmax, xinvert)    This actually defines a soc_mixer_control structure, and then assigns the address of the structure to the Private_value field, which is the Soc_mixer_control structure:[CPP]View Plain Copy/* Mixer control/struct Soc_mixer_control {int min, max, Platform_max;   unsigned int reg, Rreg, Shift, Rshift, invert;   }; It seems that Soc_mixer_control is the true descriptor of the control's characteristics, which determines the address of the control's corresponding register, the displacement value, the maximum value, and whether it is logically reversed, and the control's put callback function and get callback function need to use this structure to access the actual registers. Let's look at the definition of the get callback function:[CPP] View Plain copy INT&NBSP;SND_SOC_GET_VOLSW (struct snd_kcontrol *kcontrol,            struct snd_ctl_elem_value *ucontrol)    {            struct soc_mixer_control *mc =                     (struct soc_ mixer_control *) kcontrol->private_value;            Struct snd_soc_codec *codec = snd_kcontrol_chip (Kcontrol);            unsigned int reg = mc->reg;            unsigned int reg2 = mc->rreg;            unsigned int shift = mc->shift;            unsigned int rshift = mc->rshift;            int max = mc->max;            unsigned int mask =  (1 << fls (max))  - 1;            unsigned int invert = mc->invert;               ucontrol->value.integer.value[0]  =                     (Snd_soc_read (Codec, reg)  >> shift)  & mask;            if  (invert)                     ucontrol->value.integer.value[0] =                            max - ucontrol->value.integer.value[0];               if  (Snd_soc_volsw_is_stereo (MC))  {                    if  (reg ==  REG2)                             ucontrol->value.integer.value[1] =                                     (Snd_soc_read (codec,  REG)  & mask;            >> rshift)          else                            ucontrol-> value.integer.value[1] =                                      (Snd_soc_read (CODEC,&NBSP;REG2)  >> shift)  & mask;                   if  ( Invert)                             ucontrol->value.integer.value[1] =                                    max - ucontrol->value.integer.value[1];            }               return 0;  }   The above code at a glance, remove the soc_mixer_control structure from the Private_value field, Using the information of the structure, the corresponding registers are accessed and the corresponding values are returned.


SOC_SINGLE_TLVSOC_SINGLE_TLV is an extension of soc_single, which is primarily used to define controls that have gain control, such as volume controllers, EQ balancers, and so on.[CPP] View Plain copy #define &NBSP;SOC_SINGLE_TLV (Xname, reg, shift, max, invert, tlv_array)  \   {       .iface = sndrv_ctl_elem_iface_mixer,  .name = xname, \           .access  = sndrv_ctl_elem_access_tlv_read |\                     SNDRV_CTL_ELEM_ACCESS_READWRITE,\            .tlv.p =  (Tlv_array), \            .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\            .put = snd_soc_put_volsw, \            .private_value =  soc_single_value (Reg,  shift, Max, invert)  }   from his definition, we can see that the definition of Private_value fields used to set register information is the same as soc_single, even put and get callback functions use the same , the only difference is to add a Tlv_array parameter and assign it to the TLV.P field. About TLV, has been explained in the Linux ALSA sound card driver's four: control device creation. User space can access the array that the TLV field points to by initiating the following two IOCTL to the control device of the sound card:         Sndrv_ctl_ioctl_tlv_read         Sndrv_ctl_ioctl_tlv_write         Sndrv_ctl_ioctl_tlv_command Usually, tlv_ An array is used to describe the mapping relationship between the set value of a register and the actual meaning it represents, and the most common is the mapping between the set value and the corresponding DB value when used for volume control, see the following example: [CPP] View Plain copy Static const declare_tlv_db_scale (mixin_boost_tlv, 0, 900, 0);       static const struct snd_kcontrol_new wm1811_snd_controls[] = {    SOC_SINGLE_TLV ("Mixinl in1lp boost volume",  wm8994_input_mixer_1, 7,  1, 0,                 &NBSP;&NBSP;MIXIN_BOOST_TLV),   SOC_SINGLE_TLV ("Mixinl in1rp boost volume",  wm8994_input_mixer_1, 8, 1, 0,            &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;MIXIN_BOOST_TLV),  };   DECLARE_TLV_DB_ SCALE is used to define the Tlv_array of a DB value mapping, the above example shows that the TLV type is Sndrv_ctl_tlvt_db_scale, the minimum value of the register corresponds to 0dB, and registers each increment of one unit value, The corresponding number of DB increases is 9dB (0.01db*900), and the next two sets of SOC_SINGLE_TLV definitions show that we have defined two boost controls, and the address of the registers is Wm8994_input_mixer_ 1, the control bit is 7bit and 8bit respectively, the maximum is 1, so the control can only set two values 0 and 1, the corresponding DB value is 0dB and 9dB.

soc_doubleWith Soc_single, the difference is that soc_single only control a variable, and soc_double can simultaneously control two similar variables in a register, the most common is used for some of the stereo control, we need to control the left and right channels, because more than one channel , the parameter also has a shift-offset value corresponding to the[CPP]View Plain copy #define Soc_double (XName, Reg, Shift_left, Shift_right, max, invert) \ {. Iface = Sndrv_ctl_elem_i Face_mixer,. Name = (xname), \. info = SND_SOC_INFO_VOLSW,. get = SND_SOC_GET_VOLSW, \. put = Snd_soc_p                                             UT_VOLSW, \. Private_value = Soc_double_value (Reg, Shift_left, shift_right, \ Max, invert)}
Soc_double_rSimilar to the soc_double, for the left and right channel control registers are not the same situation, using Soc_double_r to define, parameters need to specify two register addresses.

SOC_DOUBLE_TLV the stereo version corresponding to the SOC_SINGLE_TLV, typically used for the definition of a stereo volume control.

SOC_DOUBLE_R_TLV SOC_DOUBLE_TLV version mixer control with independent register control in left and right channels

The mixer control is used for routing control of the audio channel, consisting of multiple inputs and one output, and multiple inputs are freely mixed together to form a blended output:


Fig. 1 Mixer Mixer

For mixer controls, we can think of a combination of multiple simple controls, and usually we will define a simple control for each input of mixer to control the opening and closing of the input, in the code, to define a soc_kcontrol_new array: [CPP ] View plain copy static const struct Snd_kcontrol_new left_speaker_mixer[] = {Soc_single ("Input Switch", wm8993_s Peaker_mixer, 7, 1, 0), Soc_single ("IN1LP switch", Wm8993_speaker_mixer, 5, 1, 0), Soc_single ("Output switch", wm8993_ Speaker_mixer, 3, 1, 0), Soc_single ("DAC Switch", Wm8993_speaker_mixer, 6, 1, 0),};

The above mixer uses the first 3,5,6,7 bit of the register wm8993_speaker_mixer to control the opening and closing of 4 input terminals respectively. MUX Control

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.