The objective of ASoc design is to provide better ALSA support for the embedded system chip processor audio unit or external audio decoding chip.
ASoC has multiple components to form snd_soc_platform/snd_soc_codec/snd_soc_dai/snd_soc_card and ALSA snd_pcm
Snd_soc_platform and snd_soc_codec are indispensable for the relationship between the platform and the device. snd_soc_card is an object of their instantiation.
Snd_soc_dai is the digital audio interface of snd_soc_platform and snd_soc_codec. dai of snd_soc_codec is codec_dai, and dai of snd_soc_platform is cpu_dai.
Snd_pcm is the sound card type registered after snd_soc_card is instantiated
In the sound/soc/soc-core.c, the chain table header of the four important struct mentioned above is initialized.
[Cpp] static LIST_HEAD (card_list );
Static LIST_HEAD (dai_list );
Static LIST_HEAD (platform_list );
Static LIST_HEAD (codec_list );
Static LIST_HEAD (card_list );
Static LIST_HEAD (dai_list );
Static LIST_HEAD (platform_list );
Static LIST_HEAD (codec_list );
Part 9 soc sound card device snd_soc_card
1. soc sound card device
[Cpp] struct snd_soc_card {
Const char * name; // device name
Struct device * dev; // device File
Struct snd_card * snd_card; // sound card
Struct module * owner;
Struct list_head list;
Struct mutex;
Bool instantiated; // instantiate the flag
Int (* probe) (struct platform_device * pdev );
Int (* remove) (struct platform_device * pdev );
/* The pre and post PM functions are used to do any PM work before and after the codec and DAI's do any PM work .*/
Int (* suspend_pre) (struct platform_device * pdev, pm_message_t state );
Int (* suspend_post) (struct platform_device * pdev, pm_message_t state );
Int (* resume_pre) (struct platform_device * pdev );
Int (* resume_post) (struct platform_device * pdev );
/* Callbacks */
Int (* set_bias_level) (struct snd_soc_card *, enum snd_soc_bias_level level );
Long pmdown_time;
/* CPU <--> Codec DAI links */
Struct snd_soc_dai_link * dai_link; // dai link
Int num_links;
Struct snd_soc_pcm_runtime * rtd;
Int num_rtd;
Struct work_struct deferred_resume_work;
/* Lists of probed devices belonging to this card */
Struct list_head codec_dev_list;
Struct list_head platform_dev_list;
Struct list_head dai_dev_list;
};
Struct snd_soc_card {
Const char * name; // device name
Struct device * dev; // device File
Struct snd_card * snd_card; // sound card
Struct module * owner;
Struct list_head list;
Struct mutex;
Bool instantiated; // instantiate the flag
Int (* probe) (struct platform_device * pdev );
Int (* remove) (struct platform_device * pdev );
/* The pre and post PM functions are used to do any PM work before and after the codec and DAI's do any PM work .*/
Int (* suspend_pre) (struct platform_device * pdev, pm_message_t state );
Int (* suspend_post) (struct platform_device * pdev, pm_message_t state );
Int (* resume_pre) (struct platform_device * pdev );
Int (* resume_post) (struct platform_device * pdev );
/* Callbacks */
Int (* set_bias_level) (struct snd_soc_card *, enum snd_soc_bias_level level );
Long pmdown_time;
/* CPU <--> Codec DAI links */
Struct snd_soc_dai_link * dai_link; // dai link
Int num_links;
Struct snd_soc_pcm_runtime * rtd;
Int num_rtd;
Struct work_struct deferred_resume_work;
/* Lists of probed devices belonging to this card */
Struct list_head codec_dev_list;
Struct list_head platform_dev_list;
Struct list_head dai_dev_list;
};
Snd_soc_card contains snd_card, which can be understood as an encapsulation of the audio card driver.
2. soc pcm
[Cpp] struct snd_soc_pcm_runtime {
Struct device dev; // The device file.
Struct snd_soc_card * card; // soc sound card device
Struct snd_soc_dai_link * dai_link; // dai link
Unsigned int complete: 1;
Unsigned int dev_registered: 1;
/* Transport ry data-only valid if transport ry is being enforced */
Unsigned int rate;
Long pmdown_time;
/* Runtime devices */
Struct snd_pcm * pcm; // pcm Structure
Struct snd_soc_codec * codec; // codec Device
Struct snd_soc_platform * platform; // soc platform Device
Struct snd_soc_dai * codec_dai; // codec of the dai Device
Struct snd_soc_dai * cpu_dai; // cpu of the dai Device
Struct delayed_work;
};
Struct snd_soc_pcm_runtime {
Struct device dev; // The device file.
Struct snd_soc_card * card; // soc sound card device
Struct snd_soc_dai_link * dai_link; // dai link
Unsigned int complete: 1;
Unsigned int dev_registered: 1;
/* Transport ry data-only valid if transport ry is being enforced */
Unsigned int rate;
Long pmdown_time;
/* Runtime devices */
Struct snd_pcm * pcm; // pcm Structure
Struct snd_soc_codec * codec; // codec Device
Struct snd_soc_platform * platform; // soc platform Device
Struct snd_soc_dai * codec_dai; // codec of the dai Device
Struct snd_soc_dai * cpu_dai; // cpu of the dai Device
Struct delayed_work;
};
The snd_soc_pcm_runtime struct contains an snd_pcm struct. Therefore, it can be considered as an encapsulation of pcm Sound Card equipment. Secondly, it is also a link of Asoc components.
3. soc sound card device matching process
A platform device driver is defined in the sound/soc/soc-core.c
[Cpp] static struct platform_driver soc_driver = {
. Driver = {
. Name = "soc-audio ",
. Owner = THIS_MODULE,
. Pm = & soc_pm_ops,
},
. Probe = soc_probe,
. Remove = soc_remove,
};
Static struct platform_driver soc_driver = {
. Driver = {
. Name = "soc-audio ",
. Owner = THIS_MODULE,
. Pm = & soc_pm_ops,
},
. Probe = soc_probe,
. Remove = soc_remove,
}. We know the matching between platform device drivers and platform devices. driver. name, that is, in another code, the platform device platform_device must be defined and the device name must be "soc-audio ",
In this way, the platform device and the driver can match to call the probe method of the platform driver.
Therefore, generally, the driver of the sound card designs the platform device in the following format:
[Cpp] int ret;
Static struct platform_device * xxx;
Xxx = platform_device_alloc ("soc-audio", 0); // allocate platform drivers
// Add platform Resources
Ret = platform_device_add (xxx); // Add a platform device
If (ret)
Platform_device_put (xxx); // Add reference count
Int ret;
Static struct platform_device * xxx;
Xxx = platform_device_alloc ("soc-audio", 0); // allocate platform drivers
// Add platform Resources
Ret = platform_device_add (xxx); // Add a platform device
If (ret)
Platform_device_put (xxx); // Add reference count
4. Match the called probe method soc_probe
[Cpp] static int soc_probe (struct platform_device * pdev)
{
Struct snd_soc_card * card = platform_get_drvdata (pdev); // gets the soc sound card device
Int ret = 0;
/* Bodge while we unpick instantiation */
Card-> dev = & pdev-> dev;
INIT_LIST_HEAD (& card-> dai_dev_list); // initialize the dai_dev_list linked list
INIT_LIST_HEAD (& card-> codec_dev_list); // initialize the codec_dev_list linked list
INIT_LIST_HEAD (& card-> platform_dev_list); // initialize the platform_dev_list linked list
Ret = snd_soc_register_card (card); // register the soc sound card device
If (ret! = 0 ){
Dev_err (& pdev-> dev, "Failed to register card \ n ");
Return ret;
}
Return 0;
}
Static int soc_probe (struct platform_device * pdev)
{
Struct snd_soc_card * card = platform_get_drvdata (pdev); // gets the soc sound card device
Int ret = 0;
/* Bodge while we unpick instantiation */
Card-> dev = & pdev-> dev;
INIT_LIST_HEAD (& card-> dai_dev_list); // initialize the dai_dev_list linked list
INIT_LIST_HEAD (& card-> codec_dev_list); // initialize the codec_dev_list linked list
INIT_LIST_HEAD (& card-> platform_dev_list); // initialize the platform_dev_list linked list
Ret = snd_soc_register_card (card); // register the soc sound card device
If (ret! = 0 ){
Dev_err (& pdev-> dev, "Failed to register card \ n ");
Return ret;
}
Return 0;
} Snd_soc_register_card is called to register the soc sound card device.
5. register an soc sound card device
[Cpp] static int snd_soc_register_card (struct snd_soc_card * card)
{
Int I;
If (! Card-> name |! Card-> dev)
Return-EINVAL;
Card-> rtd = kzarloc (sizeof (struct snd_soc_pcm_runtime) * card-> num_links, GFP_KERNEL); // allocate multiple soc pcm memories
If (card-> rtd = NULL)
Return-ENOMEM;
For (I = 0; I <card-> num_links; I ++)
Card-> rtd [I]. dai_link = & card-> dai_link [I]; // dai link Array
INIT_LIST_HEAD (& card-> list );
Card-> instantiated = 0; // set the soc sound card instantiation flag to 0
Mutex_init (& card-> mutex );
Mutex_lock (& client_mutex );
List_add (& card-> list, & card_list); // Add the soc sound card to the global card_list linked list
Snd_soc_instantiate_cards (); // instantiate all soc sound cards
Mutex_unlock (& client_mutex );
Dev_dbg (card-> dev, "Registered card '% s' \ n", card-> name );
Return 0;
}