On 07/05/2017 10:40 AM, Takashi Iwai wrote:
> On Wed, 05 Jul 2017 10:15:35 +0200,
> Kuninori Morimoto wrote:
>>
>>
>> From: Kuninori Morimoto <[email protected]>
>>
>> Current hdmi-codec driver is using hdmi_controls for "ELD" control.
>> But, hdmi-codec driver might be used from many HDMIs. In such case,
>> they will use same "ELD" name and kernel will indicate below error.
>>
>>      xxx: control x:x:x:ELD:x is already present
>>
>> hdmi_controls will be registered in soc_probe_component(), and we can
>> replace it by component driver probe function.
>>
>> This patch registers current hdmi_controls in new hdmi_probe().
>> If hdmi-codec is used from only 1 device, it will use "ELD" as control name
>> (We can keep compatibility).
>> If hdmi-codec is used from many devices, it will use "ELD.x" as control name.
> 
> The de facto standard way as HD-audio does is to pass the device
> number of each ELD control as same as the corresponding PCM stream
> number.
> 
> 
> thanks,
> 
> Takashi
> 
In theory, hdmi_codec_pcm_new already does the job.
snd_pcm_add_chmap_ctls instantiates the controls using PCM device ID. So
you should observe (with amixer) 2 controls with same name but not same
device ID.

Regards
Arnaud

>> Signed-off-by: Kuninori Morimoto <[email protected]>
>> ---
>>  sound/soc/codecs/hdmi-codec.c | 60 
>> +++++++++++++++++++++++++++++++++----------
>>  1 file changed, 46 insertions(+), 14 deletions(-)
>>
>> diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
>> index 22ed0dc..5835a90 100644
>> --- a/sound/soc/codecs/hdmi-codec.c
>> +++ b/sound/soc/codecs/hdmi-codec.c
>> @@ -276,6 +276,7 @@ struct hdmi_codec_cea_spk_alloc {
>>        .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
>>  };
>>  
>> +#define ELD_NAME_SIZE       8
>>  struct hdmi_codec_priv {
>>      struct hdmi_codec_pdata hcd;
>>      struct snd_soc_dai_driver *daidrv;
>> @@ -284,7 +285,10 @@ struct hdmi_codec_priv {
>>      struct snd_pcm_substream *current_stream;
>>      uint8_t eld[MAX_ELD_BYTES];
>>      struct snd_pcm_chmap *chmap_info;
>> +    struct snd_kcontrol_new control;
>>      unsigned int chmap_idx;
>> +    int id;
>> +    char eld_name[ELD_NAME_SIZE];
>>  };
>>  
>>  static const struct snd_soc_dapm_widget hdmi_widgets[] = {
>> @@ -399,18 +403,6 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol 
>> *kcontrol,
>>      return 0;
>>  }
>>  
>> -
>> -static const struct snd_kcontrol_new hdmi_controls[] = {
>> -    {
>> -            .access = SNDRV_CTL_ELEM_ACCESS_READ |
>> -                      SNDRV_CTL_ELEM_ACCESS_VOLATILE,
>> -            .iface = SNDRV_CTL_ELEM_IFACE_PCM,
>> -            .name = "ELD",
>> -            .info = hdmi_eld_ctl_info,
>> -            .get = hdmi_eld_ctl_get,
>> -    },
>> -};
>> -
>>  static int hdmi_codec_new_stream(struct snd_pcm_substream *substream,
>>                               struct snd_soc_dai *dai)
>>  {
>> @@ -718,6 +710,45 @@ static int hdmi_codec_pcm_new(struct 
>> snd_soc_pcm_runtime *rtd,
>>      .pcm_new = hdmi_codec_pcm_new,
>>  };
>>  
>> +static int hdmi_last_id = 0;
>> +static int hdmi_probe(struct snd_soc_component *component)
>> +{
>> +    struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
>> +    static struct snd_soc_component *component_1st = NULL;
>> +    char *name = "ELD";
>> +
>> +    /*
>> +     * It will use "ELD"   if hdmi_codec was used from only 1 device.
>> +     * It will use "ELD.x" if hdmi_codec was used from many devices.
>> +     * Then, first "ELD" will be replaced to "ELD.0"
>> +     */
>> +    snprintf(hcp->eld_name, ELD_NAME_SIZE, "ELD.%d", hcp->id);
>> +
>> +    if (hcp->id == 0)
>> +            component_1st = component;
>> +
>> +    if (hdmi_last_id > 1) {
>> +            name = hcp->eld_name;
>> +
>> +            if (component_1st) {
>> +                    struct hdmi_codec_priv *hcp_1st;
>> +
>> +                    /* replaced 1st "ELD" to "ELD.0" */
>> +                    hcp_1st = snd_soc_component_get_drvdata(component_1st);
>> +                    hcp_1st->control.name = hcp_1st->eld_name;
>> +            }
>> +    }
>> +
>> +    hcp->control.access     = SNDRV_CTL_ELEM_ACCESS_READ |
>> +                              SNDRV_CTL_ELEM_ACCESS_VOLATILE;
>> +    hcp->control.iface      = SNDRV_CTL_ELEM_IFACE_PCM;
>> +    hcp->control.name       = name;
>> +    hcp->control.info       = hdmi_eld_ctl_info;
>> +    hcp->control.get        = hdmi_eld_ctl_get;
>> +
>> +    return snd_soc_add_component_controls(component, &hcp->control, 1);
>> +}
>> +
>>  static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
>>                               struct device_node *endpoint)
>>  {
>> @@ -732,8 +763,7 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component 
>> *component,
>>  
>>  static struct snd_soc_codec_driver hdmi_codec = {
>>      .component_driver = {
>> -            .controls               = hdmi_controls,
>> -            .num_controls           = ARRAY_SIZE(hdmi_controls),
>> +            .probe                  = hdmi_probe,
>>              .dapm_widgets           = hdmi_widgets,
>>              .num_dapm_widgets       = ARRAY_SIZE(hdmi_widgets),
>>              .dapm_routes            = hdmi_routes,
>> @@ -768,6 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
>>      if (!hcp)
>>              return -ENOMEM;
>>  
>> +    hcp->id = hdmi_last_id;
>>      hcp->hcd = *hcd;
>>      mutex_init(&hcp->current_stream_lock);
>>  
>> @@ -795,6 +826,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
>>      }
>>  
>>      dev_set_drvdata(dev, hcp);
>> +    hdmi_last_id++;
>>      return 0;
>>  }
>>  
>> -- 
>> 1.9.1
>>
>>

Reply via email to