函数snd_soc_register_codec()分析

函数snd_soc_register_codec()的主要作用是注册codec到ASoC,另外呼叫函数snd_soc_register_dais()注册DAI(Digital Audio Interface).

用到了多个主要的数据结构,

1. codec相关的结构体,包括设备的结构体"snd_soc_codec" 以及设备操作的驱动 "snd_soc_codec_driver";

2. platform相关的结构体,包括设备的结构体"snd_soc_platform" 以及设备操作的驱动 "snd_soc_platform_driver";

3. DAI (Digital Audio Interface)相关的结构体,包括设备的结构体“snd_soc_dai“ 以及设备操作的驱动 "snd_soc_dai_driver";

4. 另外,包括"snd_soc_card", "snd_pcm_runtime", "snd_soc_dai_link";

对这些结构体进行详细的分析和梳理,可以比较全面地明白ALSA是如何工作的。


下面看一看函数里面做了些什么动作,

1. 为codec申请内存空间

	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
	if (codec == NULL)
		return -ENOMEM;
2. 为codec创建名称和指定类型

	/* create CODEC component name */
	codec->name = fmt_single_name(dev, &codec->id);
	if (codec->name == NULL) {
		ret = -ENOMEM;
		goto fail_codec;
	}

	if (codec_drv->compress_type)
		codec->compress_type = codec_drv->compress_type;
	else
		codec->compress_type = SND_SOC_FLAT_COMPRESSION;
3. codec的初始化,包括读写相关的操作函数(实际上是由codec_drv来打理);还包括dev和driver指针的链接。

	codec->write = codec_drv->write;
	codec->read = codec_drv->read;
	codec->volatile_register = codec_drv->volatile_register;
	codec->readable_register = codec_drv->readable_register;
	codec->writable_register = codec_drv->writable_register;
	codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
	codec->dapm.dev = dev;
	codec->dapm.codec = codec;
	codec->dapm.seq_notifier = codec_drv->seq_notifier;
	codec->dapm.stream_event = codec_drv->stream_event;
	codec->dev = dev;
	codec->driver = codec_drv;
	codec->num_dai = num_dai;
	mutex_init(&codec->mutex);
4. 下面是关于codec寄存器cache相关的操作,包括数据和操作函数(为什么不直接从codec读取而要在codec中做备份?很是奇怪)。

	/* allocate CODEC register cache */
	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
		codec->reg_size = reg_size;
		/* it is necessary to make a copy of the default register cache
		 * because in the case of using a compression type that requires
		 * the default register cache to be marked as the
		 * kernel might have freed the array by the time we initialize
		 * the cache.
		 */
		if (codec_drv->reg_cache_default) {
			codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
						      reg_size, GFP_KERNEL);
			if (!codec->reg_def_copy) {
				ret = -ENOMEM;
				goto fail_codec_name;
			}
		}
	}

	if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
		if (!codec->volatile_register)
			codec->volatile_register = snd_soc_default_volatile_register;
		if (!codec->readable_register)
			codec->readable_register = snd_soc_default_readable_register;
		if (!codec->writable_register)
			codec->writable_register = snd_soc_default_writable_register;
	}
5. 设置数据的格式(big and little endian)。

	for (i = 0; i < num_dai; i++) {
		fixup_codec_formats(&dai_drv[i].playback);
		fixup_codec_formats(&dai_drv[i].capture);
	}
6. 加入到codec的list中。

	mutex_lock(&client_mutex);
	list_add(&codec->list, &codec_list);
	mutex_unlock(&client_mutex);
7. 注册DAIs (Digital Audio Interface)

关于DAIs(Digital Audio Interface)注册的分析,请参考博文http://blog.csdn.net/jgw2008/article/details/52808044

	/* register any DAIs */
	ret = snd_soc_register_dais(dev, dai_drv, num_dai);
	if (ret < 0) {
		dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
		goto fail_codec_name;
	}

至此,函数snd_soc_register_codec()结束。


snd_soc_codec结构体定义如下,

/* SoC Audio Codec device */
struct snd_soc_codec {
	const char *name;
	const char *name_prefix;
	int id;
	struct device *dev;
	const struct snd_soc_codec_driver *driver;

	struct mutex mutex;
	struct snd_soc_card *card;
	struct list_head list;
	struct list_head card_list;
	int num_dai;
	enum snd_soc_compress_type compress_type;
	size_t reg_size;	/* reg_cache_size * reg_word_size */
	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
	int (*readable_register)(struct snd_soc_codec *, unsigned int);
	int (*writable_register)(struct snd_soc_codec *, unsigned int);

	/* runtime */
	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
	unsigned int active;
	unsigned int cache_bypass:1; /* Suppress access to the cache */
	unsigned int suspended:1; /* Codec is in suspend PM state */
	unsigned int probed:1; /* Codec has been probed */
	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
	unsigned int ac97_created:1; /* Codec has been created by SoC */
	unsigned int sysfs_registered:1; /* codec has been sysfs registered */
	unsigned int cache_init:1; /* codec cache has been initialized */
	unsigned int using_regmap:1; /* using regmap access */
	u32 cache_only;  /* Suppress writes to hardware */
	u32 cache_sync; /* Cache needs to be synced to hardware */

	/* codec IO */
	void *control_data; /* codec control (i2c/3wire) data */
	enum snd_soc_control_type control_type;
	hw_write_t hw_write;
	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
	int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
	void *reg_cache;
	const void *reg_def_copy;
	const struct snd_soc_cache_ops *cache_ops;
	struct mutex cache_rw_mutex;
	int val_bytes;

	/* dapm */
	struct snd_soc_dapm_context dapm;
	unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */

#ifdef CONFIG_DEBUG_FS
	struct dentry *debugfs_codec_root;
	struct dentry *debugfs_reg;
	struct dentry *debugfs_dapm;
#endif
};


snd_soc_codec_driver定义如下,

/* codec driver */
struct snd_soc_codec_driver {

	/* driver ops */
	int (*probe)(struct snd_soc_codec *);
	int (*remove)(struct snd_soc_codec *);
	int (*suspend)(struct snd_soc_codec *);
	int (*resume)(struct snd_soc_codec *);

	/* Default control and setup, added after probe() is run */
	const struct snd_kcontrol_new *controls;
	int num_controls;
	const struct snd_soc_dapm_widget *dapm_widgets;
	int num_dapm_widgets;
	const struct snd_soc_dapm_route *dapm_routes;
	int num_dapm_routes;

	/* codec wide operations */
	int (*set_sysclk)(struct snd_soc_codec *codec,
			  int clk_id, int source, unsigned int freq, int dir);
	int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
		unsigned int freq_in, unsigned int freq_out);

	/* codec IO */
	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
	int (*display_register)(struct snd_soc_codec *, char *,
				size_t, unsigned int);
	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
	int (*readable_register)(struct snd_soc_codec *, unsigned int);
	int (*writable_register)(struct snd_soc_codec *, unsigned int);
	unsigned int reg_cache_size;
	short reg_cache_step;
	short reg_word_size;
	const void *reg_cache_default;
	short reg_access_size;
	const struct snd_soc_reg_access *reg_access_default;
	enum snd_soc_compress_type compress_type;

	/* codec bias level */
	int (*set_bias_level)(struct snd_soc_codec *,
			      enum snd_soc_bias_level level);
	bool idle_bias_off;

	void (*seq_notifier)(struct snd_soc_dapm_context *,
			     enum snd_soc_dapm_type, int);

	/* codec stream completion event */
	int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);

	bool ignore_pmdown_time;  /* Doesn't benefit from pmdown delay */

	/* probe ordering - for components with runtime dependencies */
	int probe_order;
	int remove_order;
};







你可能感兴趣的:(ALSA,linux,driver,Audio)