int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
unsigned int dai_fmt);
+++++int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour);
+++++
/* 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);
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw);
-----int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
----- int cmd, struct snd_soc_platform *platform);
-----
int soc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_component *);
int (*resume)(struct snd_soc_component *);
+++++ /* pcm creation and destruction */
+++++ int (*pcm_new)(struct snd_soc_pcm_runtime *);
+++++ void (*pcm_free)(struct snd_pcm *);
+++++
/* DT */
int (*of_xlate_dai_name)(struct snd_soc_component *component,
struct of_phandle_args *args,
unsigned int suspended:1; /* is in suspend PM state */
struct list_head list;
+++++ struct list_head card_aux_list; /* for auxiliary bound components */
struct list_head card_list;
struct snd_soc_dai_driver *dai_drv;
void (*remove)(struct snd_soc_component *);
int (*suspend)(struct snd_soc_component *);
int (*resume)(struct snd_soc_component *);
+++++ int (*pcm_new)(struct snd_soc_pcm_runtime *);
+++++ void (*pcm_free)(struct snd_pcm *);
/* machine specific init */
int (*init)(struct snd_soc_component *component);
int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *);
----- /*
----- * For platform caused delay reporting.
----- * Optional.
----- */
----- snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
----- struct snd_soc_dai *);
-----
/* platform stream pcm ops */
const struct snd_pcm_ops *ops;
/* platform stream compress ops */
const struct snd_compr_ops *compr_ops;
-----
----- int (*bespoke_trigger)(struct snd_pcm_substream *, int);
};
struct snd_soc_dai_link_component {
const char *name;
const char *long_name;
const char *driver_name;
+++++ char dmi_longname[80];
+++++
struct device *dev;
struct snd_card *snd_card;
struct module *owner;
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
+++++ struct list_head aux_comp_list;
const struct snd_kcontrol_new *controls;
int num_controls;
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list);
+++++ INIT_LIST_HEAD(&card->aux_comp_list);
INIT_LIST_HEAD(&card->component_dev_list);
}
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
----- #define snd_soc_of_parse_card_name(card, propname) \
----- snd_soc_of_parse_card_name_from_node(card, NULL, propname)
----- int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
----- struct device_node *np,
----- const char *propname);
----- #define snd_soc_of_parse_audio_simple_widgets(card, propname)\
----- snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname)
----- int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
----- struct device_node *np,
----- const char *propname);
-----
+++++ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
+++++ const char *propname);
+++++ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+++++ const char *propname);
int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *tx_mask,
unsigned int *rx_mask,
unsigned int *slots,
unsigned int *slot_width);
----- #define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \
----- snd_soc_of_parse_audio_prefix_from_node(card, NULL, codec_conf, \
----- of_node, propname)
----- void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card,
----- struct device_node *np,
+++++ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname);
-----
----- #define snd_soc_of_parse_audio_routing(card, propname) \
----- snd_soc_of_parse_audio_routing_from_node(card, NULL, propname)
----- int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card,
----- struct device_node *np,
----- const char *propname);
-----
+++++ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
+++++ const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix,
struct device_node **bitclkmaster,
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/of.h>
+++++#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
* @card: soc card
* @id: DAI link ID to match
* @name: DAI link name to match, optional
----- * @stream name: DAI link stream name to match, optional
+++++ * @stream_name: DAI link stream name to match, optional
*
* This function will search all existing DAI links of the soc card to
* find the link of the same ID. Since DAI links may not have their
return 0;
}
+++++static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
+++++ struct snd_soc_pcm_runtime *rtd)
+++++{
+++++ int i, ret = 0;
+++++
+++++ for (i = 0; i < num_dais; ++i) {
+++++ struct snd_soc_dai_driver *drv = dais[i]->driver;
+++++
+++++ if (!rtd->dai_link->no_pcm && drv->pcm_new)
+++++ ret = drv->pcm_new(rtd, dais[i]);
+++++ if (ret < 0) {
+++++ dev_err(dais[i]->dev,
+++++ "ASoC: Failed to bind %s with pcm device\n",
+++++ dais[i]->name);
+++++ return ret;
+++++ }
+++++ }
+++++
+++++ return 0;
+++++}
+++++
static int soc_link_dai_widgets(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link,
struct snd_soc_pcm_runtime *rtd)
dai_link->stream_name, ret);
return ret;
}
+++++ ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
+++++ if (ret < 0)
+++++ return ret;
+++++ ret = soc_link_dai_pcm_new(rtd->codec_dais,
+++++ rtd->num_codecs, rtd);
+++++ if (ret < 0)
+++++ return ret;
} else {
INIT_DELAYED_WORK(&rtd->delayed_work,
codec2codec_close_delayed_work);
component->init = aux_dev->init;
component->auxiliary = 1;
+++++ list_add(&component->card_aux_list, &card->aux_comp_list);
return 0;
static int soc_probe_aux_devices(struct snd_soc_card *card)
{
----- struct snd_soc_component *comp;
+++++ struct snd_soc_component *comp, *tmp;
int order;
int ret;
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
----- list_for_each_entry(comp, &card->component_dev_list, card_list) {
----- if (!comp->auxiliary)
----- continue;
-----
+++++ list_for_each_entry_safe(comp, tmp, &card->aux_comp_list,
+++++ card_aux_list) {
if (comp->driver->probe_order == order) {
ret = soc_probe_component(card, comp);
if (ret < 0) {
comp->name, ret);
return ret;
}
+++++ list_del(&comp->card_aux_list);
}
}
}
}
EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
+++++
+++++/* Trim special characters, and replace '-' with '_' since '-' is used to
+++++ * separate different DMI fields in the card long name. Only number and
+++++ * alphabet characters and a few separator characters are kept.
+++++ */
+++++static void cleanup_dmi_name(char *name)
+++++{
+++++ int i, j = 0;
+++++
+++++ for (i = 0; name[i]; i++) {
+++++ if (isalnum(name[i]) || (name[i] == '.')
+++++ || (name[i] == '_'))
+++++ name[j++] = name[i];
+++++ else if (name[i] == '-')
+++++ name[j++] = '_';
+++++ }
+++++
+++++ name[j] = '\0';
+++++}
+++++
+++++/**
+++++ * snd_soc_set_dmi_name() - Register DMI names to card
+++++ * @card: The card to register DMI names
+++++ * @flavour: The flavour "differentiator" for the card amongst its peers.
+++++ *
+++++ * An Intel machine driver may be used by many different devices but are
+++++ * difficult for userspace to differentiate, since machine drivers ususally
+++++ * use their own name as the card short name and leave the card long name
+++++ * blank. To differentiate such devices and fix bugs due to lack of
+++++ * device-specific configurations, this function allows DMI info to be used
+++++ * as the sound card long name, in the format of
+++++ * "vendor-product-version-board"
+++++ * (Character '-' is used to separate different DMI fields here).
+++++ * This will help the user space to load the device-specific Use Case Manager
+++++ * (UCM) configurations for the card.
+++++ *
+++++ * Possible card long names may be:
+++++ * DellInc.-XPS139343-01-0310JH
+++++ * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
+++++ * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
+++++ *
+++++ * This function also supports flavoring the card longname to provide
+++++ * the extra differentiation, like "vendor-product-version-board-flavor".
+++++ *
+++++ * We only keep number and alphabet characters and a few separator characters
+++++ * in the card long name since UCM in the user space uses the card long names
+++++ * as card configuration directory names and AudoConf cannot support special
+++++ * charactors like SPACE.
+++++ *
+++++ * Returns 0 on success, otherwise a negative error code.
+++++ */
+++++int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
+++++{
+++++ const char *vendor, *product, *product_version, *board;
+++++ size_t longname_buf_size = sizeof(card->snd_card->longname);
+++++ size_t len;
+++++
+++++ if (card->long_name)
+++++ return 0; /* long name already set by driver or from DMI */
+++++
+++++ /* make up dmi long name as: vendor.product.version.board */
+++++ vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+++++ if (!vendor) {
+++++ dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
+++++ return 0;
+++++ }
+++++
+++++ snprintf(card->dmi_longname, sizeof(card->snd_card->longname),
+++++ "%s", vendor);
+++++ cleanup_dmi_name(card->dmi_longname);
+++++
+++++ product = dmi_get_system_info(DMI_PRODUCT_NAME);
+++++ if (product) {
+++++ len = strlen(card->dmi_longname);
+++++ snprintf(card->dmi_longname + len,
+++++ longname_buf_size - len,
+++++ "-%s", product);
+++++
+++++ len++; /* skip the separator "-" */
+++++ if (len < longname_buf_size)
+++++ cleanup_dmi_name(card->dmi_longname + len);
+++++
+++++ /* some vendors like Lenovo may only put a self-explanatory
+++++ * name in the product version field
+++++ */
+++++ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
+++++ if (product_version) {
+++++ len = strlen(card->dmi_longname);
+++++ snprintf(card->dmi_longname + len,
+++++ longname_buf_size - len,
+++++ "-%s", product_version);
+++++
+++++ len++;
+++++ if (len < longname_buf_size)
+++++ cleanup_dmi_name(card->dmi_longname + len);
+++++ }
+++++ }
+++++
+++++ board = dmi_get_system_info(DMI_BOARD_NAME);
+++++ if (board) {
+++++ len = strlen(card->dmi_longname);
+++++ snprintf(card->dmi_longname + len,
+++++ longname_buf_size - len,
+++++ "-%s", board);
+++++
+++++ len++;
+++++ if (len < longname_buf_size)
+++++ cleanup_dmi_name(card->dmi_longname + len);
+++++ } else if (!product) {
+++++ /* fall back to using legacy name */
+++++ dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
+++++ return 0;
+++++ }
+++++
+++++ /* Add flavour to dmi long name */
+++++ if (flavour) {
+++++ len = strlen(card->dmi_longname);
+++++ snprintf(card->dmi_longname + len,
+++++ longname_buf_size - len,
+++++ "-%s", flavour);
+++++
+++++ len++;
+++++ if (len < longname_buf_size)
+++++ cleanup_dmi_name(card->dmi_longname + len);
+++++ }
+++++
+++++ /* set the card long name */
+++++ card->long_name = card->dmi_longname;
+++++
+++++ return 0;
+++++}
+++++EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
+++++
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
component->remove = component->driver->remove;
component->suspend = component->driver->suspend;
component->resume = component->driver->resume;
+++++ component->pcm_new = component->driver->pcm_new;
+++++ component->pcm_free= component->driver->pcm_free;
dapm = &component->dapm;
dapm->dev = dev;
platform->driver->remove(platform);
}
+++++static int snd_soc_platform_drv_pcm_new(struct snd_soc_pcm_runtime *rtd)
+++++{
+++++ struct snd_soc_platform *platform = rtd->platform;
+++++
+++++ return platform->driver->pcm_new(rtd);
+++++}
+++++
+++++static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm)
+++++{
+++++ struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+++++ struct snd_soc_platform *platform = rtd->platform;
+++++
+++++ platform->driver->pcm_free(pcm);
+++++}
+++++
/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
platform->component.probe = snd_soc_platform_drv_probe;
if (platform_drv->remove)
platform->component.remove = snd_soc_platform_drv_remove;
+++++ if (platform_drv->pcm_new)
+++++ platform->component.pcm_new = snd_soc_platform_drv_pcm_new;
+++++ if (platform_drv->pcm_free)
+++++ platform->component.pcm_free = snd_soc_platform_drv_pcm_free;
#ifdef CONFIG_DEBUG_FS
platform->component.debugfs_prefix = "platform";
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
/* Retrieve a card's name from device tree */
----- int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
----- struct device_node *np,
----- const char *propname)
+++++ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
+++++ const char *propname)
{
+++++ struct device_node *np;
int ret;
if (!card->dev) {
return -EINVAL;
}
----- if (!np)
----- np = card->dev->of_node;
+++++ np = card->dev->of_node;
ret = of_property_read_string_index(np, propname, 0, &card->name);
/*
return 0;
}
----- EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node);
+++++ EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
static const struct snd_soc_dapm_widget simple_widgets[] = {
SND_SOC_DAPM_MIC("Microphone", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
};
----- int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
----- struct device_node *np,
+++++ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
const char *propname)
{
+++++ struct device_node *np = card->dev->of_node;
struct snd_soc_dapm_widget *widgets;
const char *template, *wname;
int i, j, num_widgets, ret;
----- if (!np)
----- np = card->dev->of_node;
-----
num_widgets = of_property_count_strings(np, propname);
if (num_widgets < 0) {
dev_err(card->dev,
return 0;
}
----- EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node);
+++++ EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
static int snd_soc_of_get_slot_mask(struct device_node *np,
const char *prop_name,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
----- void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card,
----- struct device_node *np,
+++++ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname)
{
+++++ struct device_node *np = card->dev->of_node;
const char *str;
int ret;
----- if (!np)
----- np = card->dev->of_node;
-----
ret = of_property_read_string(np, propname, &str);
if (ret < 0) {
/* no prefix is not error */
codec_conf->of_node = of_node;
codec_conf->name_prefix = str;
}
----- EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node);
+++++ EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
----- int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card,
----- struct device_node *np,
+++++ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
{
+++++ struct device_node *np = card->dev->of_node;
int num_routes;
struct snd_soc_dapm_route *routes;
int i, ret;
----- if (!np)
----- np = card->dev->of_node;
-----
num_routes = of_property_count_strings(np, propname);
if (num_routes < 0 || num_routes & 1) {
dev_err(card->dev,
return 0;
}
----- EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node);
+++++ EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix,
snd_soc_util_exit();
snd_soc_debugfs_exit();
-----#ifdef CONFIG_DEBUG_FS
-----#endif
platform_driver_unregister(&soc_driver);
}
module_exit(snd_soc_exit);