ALSA Architecture Analysis (II.)

Source: Internet
Author: User
Tags data structures goto

Linux ALSA Audio Driver Six: machine in ASOC architecture

As we mentioned in the previous section, ASOC is divided into machine, platform and codec, where the machine drive is responsible for coupling between platform and codec as well as parts and equipment or board-specific code, Again, refer to the previous section: The machine driver is responsible for handling some of the machine-specific controls and audio events (for example, when audio is played, an amplifier needs to be opened first); The individual platform and codec drivers are not working, It must be combined by the machine driver to complete the audio processing of the entire device.

Asoc everything from the machine driver, including the registration of sound card, binding platform and codec driver, and so on, let's start from the machine driver discussion.


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

ASOC the sound card registration as Platform Device, we have a WM8994 to assemble a Samsung's development Board SMDK as an example, WM8994 is a Wolfson production of multi-functional codec chip.

The code is located at:/sound/soc/samsung/smdk_wm8994.c, we are concerned with the initialization function of the module: [CPP] view plain copy print?          static int __init smdk_audio_init (void) {int ret;       Smdk_snd_device = Platform_device_alloc ("Soc-audio",-1);          if (!smdk_snd_device) Return-enomem;          Platform_set_drvdata (Smdk_snd_device, &SMDK);       ret = Platform_device_add (smdk_snd_device);          if (ret) platform_device_put (smdk_snd_device);   return ret; }


This shows that the module initialization, registered a platform device named Soc-audio, while the SMDK set to the platform_device structure of the Dev.drvdata field, which leads to the first data structure SND_SOC_ Card instance SMDK, his definition is as follows:[CPP] View Plain copy print? static struct snd_soc_dai_link smdk_dai[] = {       {  /* Primary DAI i/f */           . name =  "WM8994 AIF1",           .stream_name  =  "Pri_dai",           .cpu_dai_name =  " samsung-i2s.0 ",           .codec_dai_name = " Wm8994-aif1 ",           .platform_name = " Samsung-audio ",           .codec_name = " Wm8994-codec ",           .init = smdk_wm8994_init_ paiftx,           .ops = &smdk_ops,       }, { /* sec_fifo playback i/f */            .name =  "Sec_fifo tx",            .stream_name =  "Sec_dai",            .cpu_dai_name =  "Samsung-i2s.4",            codec_dai_name =  "WM8994-AIF1",           .platform _name =  "Samsung-audio",           .codec_name  =  "Wm8994-codec",           .ops = & smdk_ops,       },  };      static struct  snd_soc_card smdk = {       .name =  "Smdk-i2s",        .owner = this_module,       .DAI_LINK = SMDK _dai,       .num_links = array_size (smdk_dai),  };   

Through the Snd_soc_card structure, but also leads to the machine drive two other data structures: Snd_soc_dai_link (example: smdk_dai[]) Snd_soc_ops (example: smdk_ops)

In Snd_soc_dai_link, the names of platform, Codec, Codec_dai, and Cpu_dai are specified, and later machine drivers will use these names to match the Platform,codec,dai already registered in the system. These registered parts are defined in the corresponding platform drive and codec-driven code files, so that the machine-driven device initialization code is simply choosing the right platform and codec and Dai, filling them with several data structures, Then register the platform device. Of course also to implement the connection platform and codec dai_link corresponding OPS implementation, this example is smdk_ops, it only implements the Hw_params function: Smdk_hw_params. 2. Registered Platform Driver

According to the model of Linux equipment, there are platform_device, there must be platform_driver. ASOC's platform_driver is defined in the following file: Sound/soc/soc-core.c.

Or start at the entrance of the module: [CPP] view plain copy print?   static int __init snd_soc_init (void) {... return platform_driver_register (&soc_driver); }

The

Soc_driver is defined as follows: [CPP] view plain copy print?/* asoc platform driver */    static struct platform_driver soc_driver = {        .driver     = {            .name       =  "Soc-audio",            .owner      = THIS_MODULE,            .pm     = &soc_pm_ops,       },       .probe      =  soc_probe,       .remove     = soc_remove,   };  

We see Platform_driver's Name field Soc-audio, exactly the same as in Platform_device, according to the Linux device model, the platform bus matches the two names of device and driver, It also triggers the soc_probe call, which is the portal of the entire ASOC-driven initialization. 3. Initialization of the entrance Soc_probe ()

The Soc_probe function itself is simple, it takes the Snd_soc_card out of the Platform_device parameter, and then calls Snd_soc_register_card, through Snd_soc_register_card, for Snd_ The Soc_pcm_runtime array applies memory, each dai_link corresponds to a unit of the Snd_soc_pcm_runtime array, and then copies the Dai_link configuration in Snd_soc_card to the corresponding snd_soc_pcm_ runtime, and finally, most of the work is done in Snd_soc_instantiate_card, and here's a look at what Snd_soc_instantiate_card did:

The function first uses card->instantiated to determine whether the card has been instantiated, if it has been instantiated to return directly, otherwise traversing each pair of Dai_link, codec, platform, Dai binding work, the next is only part of the Code selection section, For detailed code, refer directly to the complete code tree. [CPP] view plain copy print? /* Bind DAIs */for (i = 0; i < card->num_links; i++) Soc_bind_dai_link (card, i);

The

ASOC defines three global chain header variables: codec_list, Dai_list, platform_list, all codec, Dai, and platform in the system are connected to these three global lists when registering. The Soc_bind_dai_link function scans each of these three lists, matching them according to the names in card->dai_link[], and assigns the corresponding Codec,dai and platform instances to card->rtd[after the match (Snd_ Soc_pcm_runtime). After this process, Snd_soc_pcm_runtime: (CARD->RTD) saves the Codec,dai and platform-driven information used in this machine.

Snd_soc_instantiate_card then initializes the codec register cache and then invokes the standard ALSA function to create an instance of the sound card: [CPP] view plain copy print?           /* Card bind complete so register a sound card */ret = snd_card_create (sndrv_default_idx1, SNDRV_DEFAULT_STR1,   Card->owner, 0, &card->snd_card);      Card->snd_card->dev = card->dev;   Card->dapm.bias_level = Snd_soc_bias_off;   Card->dapm.dev = card->dev;   Card->dapm.card = Card; List_add (&card->dapm.list, &card->dapm_list);


Then, call the probe function of each child structure in turn:[CPP] View Plain copy print? /* initialise the sound card only once */   if  (card-> Probe)  {       ret = card->probe (card);        if  (ret < 0)            goto  card_probe_error;  }     /* early dai link probe * /   for  (Order = snd_soc_comp_order_first; order <= snd_soc_comp_ order_last;           order++)  {        for  (i = 0; i < card->num_links; i++)  {           ret = soc_probe_dai_link (Card, i, order);            if  (ret < 0)  {               pr_err ("asoc: failed  to instantiate card %s: %d\n ",                   card->name, ret);                goto probe_dai_err;            }       }  }      for  (i  = 0; i < card->num_aux_devs; i++)  {        ret = soc_probe_aux_dev (card, i);       if  (ret  < 0)  {           pr_err ("asoc: failed  to add auxiliary devices %s: %d\n ",           &nBsp;       card->name, ret);            goto probe_aux_dev_err;       }  }   }

Do a lot of things in the Soc_probe_dai_link () function above, and get him started on the discussion:
[CPP] View Plain copy print? Static int soc_probe_dai_link (struct snd_soc_card *card, int num, int  Order)    {           ......        /* set default power off timeout */        rtd->pmdown_time = pmdown_time;          /*  probe the cpu_dai */       if  (!cpu_dai->probed & &               cpu_dai->driver- >probe_order == order)  {               if  (cpu_dai->driver->probe)  {                ret = cpu_dai->driver->probe (Cpu_dai);           }           cpu_ dai->probed = 1;   &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;/*&NBSP;MARK&NBSP;CPU _dai as probed and add to card dai list */            list_add (&cpu_dai->card_list, &card->dai_dev_list );       }          /* probe the  CODEC */       if  (!codec->probed &&               codec->driver->probe_order  == order)  {           ret = soc_probe_ Codec (CARD,&NBSP;CODEC);       }          / * probe the platform */       if  (!platform->probed & &               platform->driver- >probe_order == order)  {           ret  = soc_probe_platform (card, platform);       }           /* probe the CODEC DAI */        if  (!codec_dai->probed && codec_dai->driver->probe_order ==  Order)  {           if  (codec_dai->driver-> Probe)  {               ret =  codec_dai->driver->probe (Codec_dai);           }               /* mark codec_dai as probed  and add to card dai list */            codec_dai->probed = 1;            List_add (&codec_dai->card_list, &card->dai_dev_list);       }           /* complete dai probe during last  probe */       if  (Order != snd_soc_comp_order_last)            return 0;           ret = soc_post_component_init (card, codec, num, 0);        if  (ret)            return ret;    &NBSP;&NBsp;      ......       /* create the  pcm */   &NBSP;&NBSP;&NBSP;&NBSP;RET&NBSP;=&NBSP;SOC_NEW_PCM (rtd, num);            ........       return 0;   }  

The function, which calls the Codec,dai and platform-driven probe functions, also calls the SOC_NEW_PCM () function to create a standard ALSA-driven PCM logic device at the end. Now post some of the code for the function as well:


[CPP] view plain copy print? /* Create a new PCM */int soc_new_pcm (struct snd_soc_pcm_runtime *rtd, int num) {... struct snd_pcm_o          PS *soc_pcm_ops = &rtd->ops; Soc_pcm_ops->open = Soc_pcm_open

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.