[alsa-devel] [PATCH V5 1/2] ASoC: core: add API for registering DMI card names

Han Lu han.lu at linux.intel.com
Wed Apr 6 08:15:26 CEST 2016


Hi,

On 04/06/2016 01:47 PM, Takashi Sakamoto wrote:
> Hi,
>
> On Apr 6 2016 13:23, Han Lu wrote:
>>
>>
>> On 04/05/2016 01:38 PM, Takashi Sakamoto wrote:
>>> Hi,
>>>
>>> On Apr 5 2016 13:26, han.lu at intel.com wrote:
>>>> From: "Lu, Han" <han.lu at intel.com>
>>>>
>>>> Add core API for registering DMI card names, so user space utils such
>>>> as PA and UCM can distinguish various products.
>>>> Previously on ASoC, the card short name, driver name and long name are
>>>> all the same as the machine driver name.
>>>> The patch adds more board information:
>>>>    card driver name --->  machine driver name
>>>>    card short name  --->  DMI_BOARD_NAME or DMI_PRODUCT_NAME
>>>>    card long name and
>>>>    card component   --->  short name;driver name;(DMI_SYS_VENDOR,
>>>>                           optional);(the firmware name, optional)
>>>>
>>>> Signed-off-by: Lu, Han <han.lu at intel.com>
>>>>
>>>> diff --git a/include/sound/soc.h b/include/sound/soc.h
>>>> index 02b4a21..4e80444 100644
>>>> --- a/include/sound/soc.h
>>>> +++ b/include/sound/soc.h
>>>> @@ -486,6 +486,9 @@ void snd_soc_runtime_deactivate(struct
>>>> snd_soc_pcm_runtime *rtd, int stream);
>>>>   int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
>>>>       unsigned int dai_fmt);
>>>>
>>>> +int snd_soc_set_card_names(struct snd_soc_card *card, const char
>>>> *board,
>>>> +        const char *vendor, const char *firmware);
>>>> +
>>>>   /* Utility functions to get clock rates from various things */
>>>>   int snd_soc_calc_frame_size(int sample_size, int channels, int
>>>> tdm_slots);
>>>>   int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
>>>> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
>>>> index d2e62b15..a06b9b9 100644
>>>> --- a/sound/soc/soc-core.c
>>>> +++ b/sound/soc/soc-core.c
>>>> @@ -48,6 +48,9 @@
>>>>
>>>>   #define NAME_SIZE    32
>>>>
>>>> +#define LONGNAME_SIZE    80    /* size of longname[] in struct
>>>> snd_card */
>>>> +static char card_longname[LONGNAME_SIZE];
>>>> +
>>>
>>> I'm not a developer for SoC sound interfaces or Skylake something,
>>> however I wonder the reason to add fiile local variable for this
>>> purpose. Could I request your intension about it?
>>>
>>> Here, I assume a platform with some sound intefaces (I don't know we
>>> rarely have the situation or not). If several drivers are probed for
>>> these interfaces, the 'snd_soc_set_card_names()' might cause a race
>>> condition between the drivers against the local variable. However,
>>> there's no usage of lock primitive.
>>> Additionally, when probing processing finishes for the second driver,
>>> the local variable changes its contents. Then, ALSA core returns the
>>> renewed string as the component of the first driver. This is not good.
>>>
>>> If it's too rare that a platform with several interfaces, please
>>> inform it to me.
>> Thanks for reviewing.
>> I allocated an array here just intending for drivers to store
>> card->long_name, since I
>> assumed (by mistake) that one platform has only one interface.
>> I'll use dynamic allocate and cleanup instead.
>
> For example, we can see Allwinner A31 has two interfaces for audio 
> functionality. See clause '8.9. DIGITAL AUDIO INTERFACE' and '7.5.2. 
> HDMI BLOCK DIAGRAM' in this user manual:
>
> http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf 
>
>
> The data for these interfaces is transferred by different DMA 
> contexts, thus I can assume a different driver is developed for each 
> interface. Depending on the driver implementations, your code might 
> cause a bug for them.
>
> (I'm not a developer for SoC interface, so have no detail about it, of 
> cource.)
>
>
> As another advice, when you add static variable to keep it in ELF 
> .data section and the variable is just referred to by one function, 
> it's better to constrain the scope of the variable by adding it inner 
> the function. For example, in your case, this is better practice:
>
> int snd_soc_set_card_names(struct snd_soc_card *card,
>                            const char *board,
>                            const char *vendor, const char *firmware)
> {
>     static char card_longname[LONGNAME_SIZE];
>     ...
>
> Please notice that callers are still under the race condition against 
> the variable.
Thanks for comment. I agree that it's not a good idea to use static 
array here anyway.
So I used kmalloc() and kfree() in patch V6.

BR,
Han
>
>
> Regards
>
> Takashi Sakamoto
>
>> BR,
>> Han
>>>
>>>>   #ifdef CONFIG_DEBUG_FS
>>>>   struct dentry *snd_soc_debugfs_root;
>>>>   EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
>>>> @@ -1828,6 +1831,70 @@ int snd_soc_runtime_set_dai_fmt(struct
>>>> snd_soc_pcm_runtime *rtd,
>>>>   }
>>>>   EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
>>>>
>>>> +/**
>>>> + * snd_soc_set_card_names() - Register DMI names to card
>>>> + * @card: The card to register DMI names
>>>> + * @board: DMI_BOARD_NAME or DMI_PRODUCT_NAME
>>>> + * @vendor: DMI_SYS_VENDOR, optional
>>>> + * @firmware: The firmware name, optional
>>>> + *
>>>> + * This function registers DMI names to card for the userspace to
>>>> distinguish
>>>> + * different boards/products:
>>>> + *   card driver name --->  machine driver name
>>>> + *   card short name  --->  DMI_BOARD_NAME or DMI_PRODUCT_NAME
>>>> + *   card long name and
>>>> + *   card component   --->  short name;driver name;(DMI_SYS_VENDOR,
>>>> optional)
>>>> + *                          ;(firmware name, optional)
>>>> + *
>>>> + * Returns 0 on success, otherwise a negative error code.
>>>> + */
>>>> +int snd_soc_set_card_names(struct snd_soc_card *card, const char
>>>> *board,
>>>> +        const char *vendor, const char *firmware)
>>>> +{
>>>> +    int ret = 0;
>>>> +    size_t name_size;
>>>> +
>>>> +    if (!board) {
>>>> +        dev_err(card->dev, "ASoC: the board/product name is 
>>>> empty!\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    /* card driver name */
>>>> +    card->driver_name = card->name;
>>>> +
>>>> +    /* card short name */
>>>> +    card->name = board;
>>>> +
>>>> +    /* card long name */
>>>> +    name_size = strlen(card->name) + strlen(card->driver_name) + 4;
>>>> +    if (vendor)
>>>> +        name_size += strlen(vendor);
>>>> +    if (firmware)
>>>> +        name_size += strlen(firmware);
>>>> +    if (name_size > LONGNAME_SIZE)
>>>> +        return -ENOMEM;
>>>> +
>>>> +    snprintf(card_longname, LONGNAME_SIZE, "%s;%s;",
>>>> +            card->name, card->driver_name);
>>>> +    if (vendor)
>>>> +        strlcat(card_longname, vendor, LONGNAME_SIZE);
>>>> +    strlcat(card_longname, ";", LONGNAME_SIZE);
>>>> +    if (firmware)
>>>> +        strlcat(card_longname, firmware, LONGNAME_SIZE);
>>>> +
>>>> +    card->long_name = card_longname;
>>>> +
>>>> +    /* card component */
>>>> +    if (sizeof(card->snd_card->components) < name_size
>>>> +            + strlen(card->snd_card->components))
>>>> +        return -ENOMEM;
>>>> +
>>>> +    ret = snd_component_add(card->snd_card, card->long_name);
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(snd_soc_set_card_names);
>>>> +
>>>>   static int snd_soc_instantiate_card(struct snd_soc_card *card)
>>>>   {
>>>>       struct snd_soc_codec *codec;
>>>
>>> Regards
>>>
>>>
>>> Takashi Sakamoto
>



More information about the Alsa-devel mailing list