ALSA SOC在Linux3.1上的一些改进
来源:互联网 发布:淘宝男装分类 编辑:程序博客网 时间:2024/05/21 17:13
2012已经到来,无论这个世界是否行将毁灭,在那之前的日子还得要继续。
Android迈进了4.0,相应的Linux内核也进入了3.x时代。之后的一个工作估计要将2.6.32的驱动移植到3.x上面来。因此趁现在有空,看看alsa在这方面有什么改动。
总的来说,架构大的改动是不大可能的。codec中几个关键结构体没有大的变化,如snd_soc_dai_ops、snd_soc_dai_driver(相当于2.6.32中的snd_soc_dai),倒是以前的snd_soc_codec_device重定义为snd_soc_codec_driver,这个算是最明显的。
注册用结构体-snd_soc_codec_driver
2.6.32:
/* codec device */struct snd_soc_codec_device {int (*probe)(struct platform_device *pdev);int (*remove)(struct platform_device *pdev);int (*suspend)(struct platform_device *pdev, pm_message_t state);int (*resume)(struct platform_device *pdev);};
3.1.1:
/* 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 *,pm_message_t state);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, 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);short 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);void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int);/* probe ordering - for components with runtime dependencies */int probe_order;int remove_order;};
位于snd_soc_codec_driver中的一些codec IO成员函数和set_bias_level回调函数原来都放在另外一个结构体snd_soc_codec中,现在放置在这里了,这是根据源码结构调整的结果。事实真正需要设置的成员也不是很多,如下:
static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {.probe = wm9713_soc_probe,.remove = wm9713_soc_remove,.suspend =wm9713_soc_suspend,.resume = wm9713_soc_resume,.read = ac97_read,.write = ac97_write,.set_bias_level = wm9713_set_bias_level,.reg_cache_size = ARRAY_SIZE(wm9713_reg),.reg_word_size = sizeof(u16),.reg_cache_step = 2,.reg_cache_default = wm9713_reg,.dapm_widgets = wm9713_dapm_widgets,.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),.dapm_routes = wm9713_audio_map,.num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),};
probe、remove、suspend、resume相信不用累述了,volatile_register函数判断指定的寄存器是否volatile,reg_cache_size一般为寄存器数目,reg_word_size为寄存器的字长,reg_cache_default为寄存器默认值配置表。
而dapm_widgets、dapm_routes就比较“犀利”了。之前的dapm widgets和routes分别通过函数snd_soc_dapm_new_controls和snd_soc_dapm_add_routes来注册的(当然现在还保留这些接口),现在则可以填入到这个结构体,在soc-core里注册,省了不少功夫:
static int soc_probe_codec(struct snd_soc_card *card, struct snd_soc_codec *codec){//...if (driver->dapm_widgets)snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, driver->num_dapm_widgets);//...if (driver->controls)snd_soc_add_controls(codec, driver->controls, driver->num_controls);if (driver->dapm_routes)snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,driver->num_dapm_routes);//...}
同时可看到dirver ops的函数参数有所不同了,以前是struct platform_device *pdev,现在改为struct snd_soc_codec *codec,这个与codec的注册函数snd_soc_register_codec和设备的drvdata有关,之后会逐一分析。
注册函数-snd_soc_register_codec
对于snd_soc_codec_driver,之前需要EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713),然后在其他地方注册,现在不用那么麻烦了:
static __devinit int wm9713_probe(struct platform_device *pdev){return snd_soc_register_codec(&pdev->dev,&soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));}
随后像普通的platform设备那样注册就行了。不再需要snd_soc_new_pcms注册pcm、snd_soc_init_card注册card。
snd_soc_register_codec函数原型:
int snd_soc_register_codec(struct device *dev,const struct snd_soc_codec_driver *codec_drv,struct snd_soc_dai_driver *dai_drv, int num_dai);其中snd_soc_dai_driver与之前的snd_soc_dai类似,没有特别需要注意的地方,初始化如:
static struct snd_soc_dai_driver wm9713_dai[] = {{.name = "wm9713-hifi",.ac97_control = 1,.playback = {.stream_name = "HiFi Playback",.channels_min = 1,.channels_max = 2,.rates = WM9713_RATES,.formats = SND_SOC_STD_AC97_FMTS,},.capture = {.stream_name = "HiFi Capture",.channels_min = 1,.channels_max = 2,.rates = WM9713_RATES,.formats = SND_SOC_STD_AC97_FMTS,},.ops = &wm9713_dai_ops_hifi,},//...//...};
注:之前的snd_soc_dai也需要EXPORT_SYMBOL_GPL的,然后在其他地方注册的,现在改进了这点,减少了export的symbol,代码架构更加清晰可靠。
设备私有数据-drvdata
在ALSA之CODEC分析中有提到“开始看到socdev = platform_get_drvdata(pdev)这句不免有点疑惑,到底pdev是在哪里初始化好了?”,这个pdev就是drvdata。这个东东非常重要,它一般包含codec自定义的私有数据,如控制接口类型(I2C/SPI/AC97)、fll_in(FLL input frequency)、fll_out(FLL output frequency)等信息。因为每种codec可能定义的私有数据体不同,而Linux内核喜欢抽象,所以就产生了drvdata。
之前drvdata的来龙去脉是百转千回绕吊瓶的,而现在版本是比较直观的,且看分析:
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,void *data){dev_set_drvdata(codec->dev, data);}static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec){return dev_get_drvdata(codec->dev);}
soc.h里实现两个函数用于设置和获取drvdata。snd_soc_codec是codec驱动里最常使用的结构体,在各个操作函数均可以看到它的身影,所以选择它和drvdata联系起来。
使用方法如下:
static int wm9713_soc_probe(struct snd_soc_codec *codec){struct wm9713_priv *wm9713;int ret = 0, reg;wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);if (wm9713 == NULL)return -ENOMEM;snd_soc_codec_set_drvdata(codec, wm9713);//...}static int wm9713_soc_remove(struct snd_soc_codec *codec){struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);snd_soc_free_ac97_codec(codec);kfree(wm9713);return 0;}
设置控制接口-snd_soc_codec_set_cache_io
这个函数在以前版本也有的,但是当时没有留意。现在发现这个函数很实用,只需要配置寄存器地址宽度、数据宽度、和控制接口类型,soc-io模块就自动会选择合适的控制接口函数。
/** * snd_soc_codec_set_cache_io: Set up standard I/O functions. * * @codec: CODEC to configure. * @addr_bits: Number of bits of register address data. * @data_bits: Number of bits of data per register. * @control: Control bus used. * * Register formats are frequently shared between many I2C and SPI * devices. In order to promote code reuse the ASoC core provides * some standard implementations of CODEC read and write operations * which can be set up using this function. * * The caller is responsible for allocating and initialising the * actual cache. * * Note that at present this code cannot be used by CODECs with * volatile registers. */int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, int addr_bits, int data_bits, enum snd_soc_control_type control){int i;for (i = 0; i < ARRAY_SIZE(io_types); i++)if (io_types[i].addr_bits == addr_bits && io_types[i].data_bits == data_bits)break;if (i == ARRAY_SIZE(io_types)) {printk(KERN_ERR "No I/O functions for %d bit address %d bit data\n", addr_bits, data_bits);return -EINVAL;}codec->write = io_types[i].write;codec->read = hw_read;codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;switch (control) {case SND_SOC_I2C:#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))codec->hw_write = (hw_write_t)i2c_master_send;#endifif (io_types[i].i2c_read)codec->hw_read = io_types[i].i2c_read;codec->control_data = container_of(codec->dev, struct i2c_client, dev);break;case SND_SOC_SPI:#ifdef CONFIG_SPI_MASTERcodec->hw_write = do_spi_write;#endifif (io_types[i].spi_read)codec->hw_read = io_types[i].spi_read;codec->control_data = container_of(codec->dev, struct spi_device, dev);break;}return 0;}EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进 .
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- ALSA SOC在Linux3.1上的一些改进
- Alsa SoC Audio(part 1)
- alsa-lib和alsa-util在TQ2416上的移植
- 华为3GE261在Android4.0、linux3.0.8内核上的移植记录1
- 在基于or1200处理器的SoC上移植linux
- ALSA SOC架构基础知识
- ALSA SOC架构
- ALSA SOC Android
- ALSA SOC架构
- asp调用webservice
- 设计模式C++学习笔记之三(Singleton单例模式)
- LESS详解之命名空间
- 二叉树
- C#中get与set(类的属性封装)
- ALSA SOC在Linux3.1上的一些改进
- IIS默认网站被删除
- hadoop配置参数说明
- Oracle之课程实验一(安装oracle)
- ORACLE 实时TOP SESSION查询
- yii CDbCriteria
- Java Math的 floor,round和ceil的总结(四舍五入等)
- 以boost::function和boost:bind取代虚函数
- 试探Galaxy的音频设计框架