Android音频驱动-ASOC之CPU DAI
来源:互联网 发布:软件开发界面 编辑:程序博客网 时间:2024/05/20 04:08
dai驱动通常对应cpu的一个或几个I2S/PCM接口,与snd_soc_platform一样,dai驱动也是实现为一个platform driver,
实现一个dai驱动大致可以分为以下几个步骤:
定义一个snd_soc_dai_driver结构的实例;通过API snd_soc_register_dais,注册snd_soc_dai实例;实现snd_soc_dai_driver结构中的probe、suspend等回调;实现snd_soc_dai_driver结构中的snd_soc_dai_ops字段中的回调函数;
struct snd_soc_dai_driver { /* DAI description */ const char *name; unsigned int id; int ac97_control; unsigned int base; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); int (*remove)(struct snd_soc_dai *dai); int (*suspend)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai); /* compress dai */ bool compress_dai; /* ops */ const struct snd_soc_dai_ops *ops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* probe ordering - for components with runtime dependencies */ int probe_order; int remove_order;};struct snd_soc_dai_ops { /* * DAI clocking configuration, all optional. * Called by soc_card drivers, normally in their hw_params. */ int (*set_sysclk)(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir); int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio); /* * DAI format configuration * Called by soc_card drivers, normally in their hw_params. */ int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); int (*xlate_tdm_slot_mask)(unsigned int slots, unsigned int *tx_mask, unsigned int *rx_mask); int (*set_tdm_slot)(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); /* * DAI digital mute - optional. * Called by soc-core to minimise any pops. */ int (*digital_mute)(struct snd_soc_dai *dai, int mute); int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream); /* * ALSA PCM audio operations - all optional. * Called by soc-core during audio PCM operations. */ int (*startup)(struct snd_pcm_substream *, struct snd_soc_dai *); void (*shutdown)(struct snd_pcm_substream *, struct snd_soc_dai *); int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *, struct snd_soc_dai *); int (*hw_free)(struct snd_pcm_substream *, struct snd_soc_dai *); int (*prepare)(struct snd_pcm_substream *, struct snd_soc_dai *); /* * NOTE: Commands passed to the trigger function are not necessarily * compatible with the current state of the dai. For example this * sequence of commands is possible: START STOP STOP. * So do not unconditionally use refcounting functions in the trigger * function, e.g. clk_enable/disable. */ int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *); int (*bespoke_trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *); /* * For hardware based FIFO caused delay reporting. * Optional. */ snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, struct snd_soc_dai *);};
static int __init mtk_dai_stub_init(void){ int ret; soc_mtk_dai_dev = platform_device_alloc(MT_SOC_DAI_NAME , -1); ret = platform_device_add(soc_mtk_dai_dev); return platform_driver_register(&mtk_dai_stub_driver);}/*static struct platform_driver mtk_dai_stub_driver = {//Linux platform driver .probe = mtk_dai_stub_dev_probe, .remove = mtk_dai_stub_dev_remove, .driver = { .name = MT_SOC_DAI_NAME, .owner = THIS_MODULE, },};static struct snd_soc_dai_ops mtk_dai_stub_ops = { .startup = multimedia_startup,};static struct snd_soc_dai_driver mtk_dai_stub_dai[] = {//cpu dai driver { .playback = { .stream_name = MT_SOC_I2SDL1_STREAM_NAME, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, .channels_min = 1, .channels_max = 2, .rate_min = 8000, .rate_max = 192000, }, .name = MT_SOC_I2S0DL1_NAME, .ops = &mtk_dai_stub_ops, }, ......}static const struct snd_soc_component_driver mt_dai_component = {//CPU DAI的所属的component driver对象 .name = MT_SOC_DAI_NAME,};*/static int mtk_dai_stub_dev_probe(struct platform_device *pdev){ int rc = 0; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); if (pdev->dev.of_node) dev_set_name(&pdev->dev, "%s", MT_SOC_DAI_NAME); rc = snd_soc_register_component(&pdev->dev, &mt_dai_component, mtk_dai_stub_dai, ARRAY_SIZE(mtk_dai_stub_dai)); return rc;}int snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, int num_dai){ struct snd_soc_component *cmpnt; int ret; cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL);//创建CPU DAI所属的component对象 ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev); cmpnt->ignore_pmdown_time = true; cmpnt->registered_as_component = true; ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);//将CPU DAI保存到component->dai_list链表中 snd_soc_component_add(cmpnt);//将component保存到全局对象component_list中 return 0;}
创建CPU DAI所属的component对象
static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev){ struct snd_soc_dapm_context *dapm; component->name = fmt_single_name(dev, &component->id); component->dev = dev; component->driver = driver;//保存mt_dai_component component->probe = component->driver->probe;//component driver对象没有实现probe函数 component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; dapm = component->dapm_ptr; dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; component->controls = driver->controls; component->num_controls = driver->num_controls; component->dapm_widgets = driver->dapm_widgets; component->num_dapm_widgets = driver->num_dapm_widgets; component->dapm_routes = driver->dapm_routes; component->num_dapm_routes = driver->num_dapm_routes; INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); return 0;}
将CPU DAI保存到component->dai_list链表中
static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count, bool legacy_dai_naming){ struct device *dev = component->dev; struct snd_soc_dai *dai; unsigned int i; int ret; component->dai_drv = dai_drv; component->num_dai = count; for (i = 0; i < count; i++) { dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); if (count == 1 && legacy_dai_naming) { dai->name = fmt_single_name(dev, &dai->id); } else { dai->name = fmt_multiple_name(dev, &dai_drv[i]); if (dai_drv[i].id) dai->id = dai_drv[i].id; else dai->id = i; } dai->component = component; dai->dev = dev; dai->driver = &dai_drv[i]; if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; list_add(&dai->list, &component->dai_list); } return 0;}
将component保存到全局对象component_list中
static void snd_soc_component_add(struct snd_soc_component *component){ mutex_lock(&client_mutex); snd_soc_component_add_unlocked(component); mutex_unlock(&client_mutex);}static void snd_soc_component_add_unlocked(struct snd_soc_component *component){ if (!component->write && !component->read) snd_soc_component_init_regmap(component); list_add(&component->list, &component_list);}
阅读全文
0 0
- Android音频驱动-ASOC之CPU DAI
- Android音频驱动-ASOC之Machine
- Android音频驱动-ASOC之Codec
- Android音频驱动-ASOC之Platform
- Android音频驱动-ASOC之PCM Open
- Android音频驱动-ASOC之常用对象
- Android音频驱动-ASOC之PCM Prepare
- Android音频驱动-ASOC之PCM Write
- Android音频驱动-ASOC之Control Open
- Android音频驱动-ASOC之DAMP
- Android音频驱动-ASOC之Sound Card注册
- Android音频驱动-ASOC之PCM Device创建
- Android音频驱动-ASOC之Sound Card创建
- Android音频驱动-ASOC之主&从设备号
- Android音频驱动-ASOC之创建设备节点
- Android音频驱动-ASOC之PCM HW Params
- Android音频驱动-ASOC之Control Device创建
- Linux音频驱动之ASoC驱动架构
- HDU 4370 0 or 1(最短路)by Kuangbin
- php socket编程
- Linux shell
- Hackerrank Equal(这特么也是dp???)
- 计算机组成原理之机器
- Android音频驱动-ASOC之CPU DAI
- oracle的max()、full join和declare
- QStackedWidget
- 华为笔试:最高分是多少(2016)
- 快速幂
- MFC CPropertySheet 多页面切换 实例
- Java JFrame
- Asp.Net Core 设置MVC
- 单例模式