• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Audio
2
3
4## Audio驱动概述
5
6多媒体系统是物联网设备开发中不可缺少的一部分,Audio作为其中重要的一个模块,Audio驱动模型的构建显得尤为重要。
7
8本文主要介绍基于HDF(Hardware Driver Foundation)驱动框架开发的Audio驱动,包括Audio驱动的架构组成和功能部件。芯片厂商可以根据此驱动架构,进行各自驱动的开发及HAL层接口的调用。
9
10
11
12## Audio驱动框架介绍
13
14Audio驱动框架基于[HDF驱动框架](driver-hdf-overview.md)实现。Audio驱动架构组成:
15
16![](figures/Audio框架图.png)
17
18驱动架构主要由以下几部分组成。
19- HDI adapter:实现Audio HAL层驱动(HDI接口适配),给Audio服务(frameworks)提供所需的音频硬件驱动能力接口。包含 Audio Manager、Audio Adapter、Audio Control、Audio Capture、Audio Render等接口对象。
20- Audio Interface Lib:配合内核中的Audio Driver Model使用,实现音频硬件的控制、录音数据的读取、播放数据的写入。它里面包括Stream_ctrl_common 通用层,主要是为了和上层的Audio HDI Adapter层进行对接。
21- ADM(Audio Driver Model):音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,对于Codec和DSP设备厂商来说,可根据ADM模块提供的向下统一接口适配各自的驱动代码,就可以实现快速开发和适配OpenHarmony系统。
22- Audio Control Dispatch: 接收lib层的控制指令并将控制指令分发到驱动层。
23- Audio Stream Dispatch: 接收lib层的数据并将数据分发到驱动层。
24
25- Card Manager: 多声卡管理模块。每个声卡含有Dai、Platform、Codec、Dsp、SAPM模块。
26- Platform Drivers: 驱动适配层。
27- SAPM(Smart Audio Power Manager):电源管理模块,对整个ADM电源进行功耗策略优化。
28
29## Audio驱动开发
30
31以下将基于Audio驱动框架,并以Hi3516DV300平台为例,介绍相关驱动开发的具体步骤。
32
33### Audio ADM模块框架介绍
34
35Audio驱动对HDI层提供三个服务hdf_audio_render、hdf_audio_capture、hdf_audio_control。开发板dev目录下驱动服务节点如下:
36
37```shell
38# ls -l hdf_audio*
39crw-rw---- 1 system system 247,   6 1970-01-01 00:00 hdf_audio_capture             // 音频数据录音流服务。
40crw-rw---- 1 root   root   247,   4 1970-01-01 00:00 hdf_audio_codec_primary_dev0  // 音频声卡设备0名称。
41crw-rw---- 1 root   root   247,   4 1970-01-01 00:00 hdf_audio_codec_primary_dev11 // 音频声卡设备1名称。
42crw-rw---- 1 system system 247,   5 1970-01-01 00:00 hdf_audio_control             // 音频控制流服务。
43crw-rw---- 1 system system 247,   7 1970-01-01 00:00 hdf_audio_render              // 音频数据播放流务。
44```
45
46音频声卡设备包括的驱动服务:
47
48hdf_audio_codec_primary_dev0
49
50- dma_service_0 : dma服务
51- dai_service : CPU dai服务
52- codec_service_0 : codec服务(可以是smartPA)
53- dsp_service_0 : dsp 服务(可选项)
54
55hdf_audio_codec_primary_dev11
56
57- dma_service_0 : dma服务
58- dai_service : CPU dai服务
59- codec_service_1 : codec服务(可以是smartPA)
60- dsp_service_0 : dsp服务(可选项)
61
62#### 启动流程
63
64![](figures/ADM启动流程图.png)
65
661. 系统启动时Audio模块的Platform、Codec、Dsp、Dai各个驱动首先被加载,各驱动从各自私有配置文件中获取配置信息,并将获取的配置信息保存到各驱动的Data数据结构中。
67
682. 各驱动模块调用ADM注册接口将自己添加到各驱动模块的链表中。
69
703. ADM模块读取hdf_audio_driver_0和hdf_audio_driver_1配置信息,加载各模块的具体设备。
71
724. ADM模块调用各模块的初始化函数对各模块设备进行初始化。
73
745. 将初始化成功的音频设备添加到cardManager链表。
75
76#### 播放流程
77
78![](figures/ADM播放流程图.png)
79
801. 播放音频时,Interface Lib层通过播放流服务下发Render Open指令,Audio Stream Dispatch服务收到指令后分别调用各模块的函数接口对指令进行下发。
81
822. Interface Lib层通过控制服务下发通路选择指令,Control Dispatch控制服务收到指令后调用Dai模块接口设置通路。
83
843. Interface Lib层通过播放流服务下发硬件参数,Audio Stream Dispatch服务收到参数后分别调用各模块参数设置接口,对硬件参数进行设置。
85
864. Interface Lib层通过播放流服务下发播放启动指令,Audio Stream Dispatch服务收到指令后分别调用各模块启动接口,对各模块进行启动设置。
87
885. Interface Lib层通过播放流服务下发音频数据,Audio Stream Dispatch服务收到数据后调用Platform AudioPcmWrite接口将音频数据传给Dma。
89
906. Interface Lib层通过播放流服务下发播放停止指令,Audio Stream Dispatch服务收到指令后分别调用各模块停止接口,对各模块进行停止设置。
91
927. Interface Lib层通过播放流服务下发Render Close指令,Audio Stream Dispatch服务收到指令后调用Platform AudioRenderClose对已申请资源进行释放。
93
94#### 控制流程
95
96![](figures/ADM控制流程图.png)
97
981. 设置音量,首先Interface Lib层通过控制服务下发获取音量范围指令,Control Dispatch控制服务收到指令后进行解析,并调用Codec模块Get函数,获取可设置音量的范围。
992. Interface Lib层通过控制服务下发设置音量指令,Control Dispatch控制服务收到指令后进行解析,并调用Codec模块Set函数设置音量。
100
101### Audio驱动公共函数介绍
102
103| 函数名                         | 功能                                        |
104| ------------------------------ | ------------------------------------------- |
105| CodecDeviceReadReg             | codec寄存器读函数                           |
106| CodecDeviceWriteReg            | codec寄存器写函数                           |
107| CodecDaiRegI2cRead             | codec dai通过I2C接口读寄存器函数            |
108| CodecDaiRegI2cWrite            | codec dai通过I2C接口写寄存器函数            |
109| CodecDeviceRegI2cRead          | codec通过I2C接口读寄存器函数                |
110| CodecDeviceRegI2cWrite         | codec通过I2C接口写寄存器函数                |
111| CodecDeviceInitRegConfig       | codec初始化函数                             |
112| CodecDaiDeviceStartupRegConfig | codec启动函数                               |
113| CodecSetCtlFunc                | codec设置set和get接口实现函数               |
114| CodecSetConfigInfoOfControls   | codec设置控制功能函数接口和寄存器信息的函数 |
115| CodecGetConfigInfo             | codec获取HCS配置信息函数                    |
116| CodecGetDaiName                | codec获取HCS配置dai名称函数                 |
117| CodecGetServiceName            | codec获取HCS配置服务名称函数                |
118| DaiDeviceReadReg               | dai读寄存器函数                             |
119| DaiDeviceWriteReg              | dai写寄存器函数                             |
120| DaiSetConfigInfoOfControls     | dai设置控制功能函数接口和寄存器信息的函数   |
121| DaiGetConfigInfo               | dai获取HCS配置信息函数                      |
122
123
124
125### Audio驱动开发步骤
126
127#### 已有平台开发
128
129ADM适配已有平台(Hi3516DV300)Codec或Smart PA的驱动开发流程:
130
131![](figures/开发流程图1.png)
132
133- 根据芯片说明将相关寄存器信息配置到Codec或Smart PA的私有HCS中。
134
135- 如果新添加Codec或Smart PA和已适配Codec或Smart PA的工作流程相同则不需要实现Codec或Smart PA的操作函数集和配置编译文件。
136
137- 进行编译调试验证。
138
139#### 新平台开发
140
141ADM适配新平台Audio驱动开发流程:
142
143![](figures/开发流程图2.png)
144
145Audio驱动需要将Audio相关的Codec(可选)、Dai、DMA、DSP(可选)、Smart PA(可选)驱动进行适配。
146
147- 根据芯片说明将各模块驱动的寄存器信息配置到各模块的私有配置文件中。
148
149- 实现各模块的操作函数集。
150
151- 修改配置Audio模块编译文件。
152
153- 进行编译调试验证。
154
155## Audio驱动开发实例
156
157代码路径:device/board/hisilicon/hispark_taurus/audio_drivers
158
159下面以Hi3516DV300为例,介绍Audio的Codec驱动、Dai驱动、Platform驱动开发步骤。
160
161### Codec驱动开发实例
162
163代码路径:device/board/hisilicon/hispark_taurus/audio_drivers/codec/hi3516
164
165codec驱动开发主要包含如下几个重要步骤:
166
1671. 定义填充一个具体的codec。
1682. 实现codec回调函数。
1693. 注册绑定到HDF框架。
1704. 配置HCS和Makefile。
171
172#### Codec数据结构填充
173
174Codec模块需要填充如下3个结构体:
175
176- g_codecData:codec设备的操作函数集和私有数据集。
177
178- g_codecDaiDeviceOps:codecDai的操作函数集,包括启动传输和参数配置等函数接口。
179
180- g_codecDaiData:codec的数字音频接口的操作函数集和私有数据集。
181
182```c
183struct CodecData g_codecData = {
184  .Init = CodecDeviceInit,      // codec设备初始化(适配新平台需重新实现)
185  .Read = AudioDeviceReadReg,   // 读寄存器(现有框架已实现可使用)
186  .Write = AudioDeviceWriteReg, // 写寄存器(现有框架已实现可使用)
187};
188
189struct AudioDaiOps g_codecDaiDeviceOps = {
190  .Startup = CodecDaiStartup,   // 启动传输(适配新平台需重新实现)
191  .HwParams = CodecDaiHwParams, // 参数配置(适配新平台需重新实现)
192};
193
194struct DaiData g_codecDaiData = {
195  .DaiInit = CodecDaiDeviceInit, // codecdai设备初始化(适配新平台需重新实现)
196  .ops = &g_codecDaiDeviceOps,   // codecdai操作函数
197};
198```
199
200#### codecDevice和codecDai设备初始化
201
202CodecDeviceInit将完成AIAO的设置、寄存器默认值初始化、g_audioControls插入到controls链、电源管理初始化、通路选择设置等。
203
204```c
205int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
206{
207    ...
208    /* hi3516平台AIAO的Set和Get注册 */
209    CodecSetCtlFunc(codec->devData, AudioCodecAiaoGetCtrlOps, AudioCodecAiaoSetCtrlOps)
210    ...
211    /* hi3516平台codec寄存器IoRemap */
212    CodecHalSysInit();
213    ...
214    /* hi3516平台codec寄存器默认值初始化 */
215    CodecRegDefaultInit(codec->devData->regCfgGroup);
216    ...
217    /* hi3516平台g_audioControls挂到Control链表上 */
218    AudioAddControls(audioCard, codec->devData->controls, codec->devData->numControls);
219    ...
220    /* hi3516平台codec加载到sapm */
221    AudioSapmNewComponents(audioCard, codec->devData->sapmComponents, codec->devData->numSapmComponent);
222    ...
223    /* hi3516平台codec加挂到通路选择链表上 */
224    AudioSapmAddRoutes(audioCard, g_audioRoutes, HDF_ARRAY_SIZE(g_audioRoutes);
225    ...
226    AudioSapmNewControls(audioCard);
227    ...
228    /* hi3516平台codec电源管理 */
229    AudioSapmSleep(audioCard);
230    ...
231    return HDF_SUCCESS;
232}
233```
234
235CodecDaiDeviceInit将完成codecDai侧初始化,hi3516此处未涉及,接口保留:
236
237```c
238int32_t CodecDaiDeviceInit(struct AudioCard *card, const struct DaiDevice *device)
239
240{
241    ...
242    AUDIO_DRIVER_LOG_DEBUG("codec dai device name: %s\n", device->devDaiName);
243    (void)card;
244    return HDF_SUCCESS;
245}
246```
247
248#### Codec操作函数集实现
249
250codec模块当前封装了OSAL读写寄存器的Read、Write函数。
251
252如新增平台无法使用OSAL的Read、Write函数来操作寄存器,则此Read、Write函数接口需自行实现。
253
254```c
255int32_t AudioDeviceReadReg(unsigned long virtualAddress, uint32_t reg, uint32_t *val)
256{
257  ...
258  *val = OSAL_READL((void *)((uintptr_t)(virtualAddress + reg)));
259  return HDF_SUCCESS;
260}
261
262int32_t AudioDeviceWriteReg(unsigned long virtualAddress, uint32_t reg, uint32_t value)
263{
264  OSAL_WRITEL(value, (void *)((uintptr_t)(virtualAddress + reg)));
265  return HDF_SUCCESS;
266}
267```
268
269CodecDaiStartup为启动时的一些设置。
270
271```c
272int32_t CodecDaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
273{
274  int32_t ret;
275  ...
276  (void)card;
277  ret = CodecSetAdcTuneEnable(device->devData->regCfgGroup);
278  ...
279  return HDF_SUCCESS;
280}
281```
282
283CodecDaiHwParams为参数配置,包括采样率、位宽等。
284
285```c
286int32_t CodecDaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
287{
288  unsigned int bitWidth;
289  struct CodecDaiParamsVal codecDaiParamsVal;
290  ...
291  int ret = AudioFormatToBitWidth(param->format, &bitWidth);
292  ...
293  codecDaiParamsVal.frequencyVal = param->rate;
294  codecDaiParamsVal.formatVal = bitWidth;
295  ret = CodecDaiParamsUpdate(card->rtd->codecDai->devData->regCfgGroup, codecDaiParamsVal);
296  ...
297  return HDF_SUCCESS;
298}
299```
300
301#### Codec注册绑定到HDF
302
303此处依赖HDF框架的驱动实现方式,具体流程可参考[HDF驱动框架](driver-hdf-overview.md)指导。
304
305填充g_codecDriverEntry结构体,moduleName与device_info.hcs中的moduleName匹配,实现Bind、Init、Release函数指针。
306
307device/board/hisilicon/hispark_taurus/audio_drivers/codec/hi3516/src/hi3516_codec_adapter.c
308
309```c
310struct HdfDriverEntry g_codecDriverEntry = {
311   .moduleVersion = 1,
312   .moduleName = "CODEC_HI3516",
313   .Bind = CodecDriverBind,
314   .Init = CodecDriverInit,
315   .Release = CodecDriverRelease,
316};
317HDF_INIT(g_codecDriverEntry);
318```
319
320CodecDriverBind:将HDF中device绑定到codec,将codec service注册到HDF框架。
321
322```c
323static int32_t CodecDriverBind(struct HdfDeviceObject *device)
324{
325  struct CodecHost *codecHost = (struct CodecHost *)OsalMemCalloc(sizeof(*codecHost));
326  ...
327  codecHost->device = device;
328  device->service = &codecHost->service;
329  return HDF_SUCCESS;
330}
331```
332
333CodecDriverInit:获取codecService名字和私有寄存器配置,并通过AudioRegisterCodec插入到链表中。
334
335```c
336static int32_t CodecDriverInit(struct HdfDeviceObject *device)
337{
338  ...
339  CodecGetConfigInfo(device, &g_codecData);
340  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
341  CodecGetServiceName(device, &g_codecData.drvCodecName);
342  CodecGetDaiName(device, &g_codecDaiData.drvDaiName);
343  AudioRegisterCodec(device, &g_codecData, &g_codecDaiData);
344  ...
345  return HDF_SUCCESS;
346}
347```
348
349CodecDriverRelease:释放驱动资源。
350
351```c
352static void CodecDriverRelease(struct HdfDeviceObject *device)
353{
354   codecHost = (struct CodecHost *)device->service;
355   OsalMemFree(codecHost);
356}
357```
358
359#### HCS配置流程<a name="section4115"></a>
360
361hcs中配置驱动节点、加载顺序、服务名称等。hcs语法可参考HDF框架的[配置管理](driver-hdf-manage.md)。
362
363标准系统配置文件路径:
364
365vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/
366
367小型系统配置文件路径:
368
369vendor/hisilicon/hispark_taurus/hdf_config/
370
371**device_info.hcs中配置Codec设备信息**
372
373添加Codec节点配置。修改如下配置中的moduleName,该名字会与HdfDriverEntry结构体中moduleName进行匹配,一般情况需体现出硬件平台名称。例:moduleName = "CODEC_HI3516"。
374
375代码片段如下:
376
377```c
378     audio :: host {
379      device_codec :: device {
380         device0 :: deviceNode {
381           policy = 1;   // codec模块只对内核提供服务
382           priority = 50;  // codec模块需在HDF_AUDIO模块之前加载
383           preload = 0;
384           permission = 0666;
385           moduleName = "CODEC_HI3516"; // 名字会与HdfDriverEntry结构体中moduleName进行匹配
386           serviceName = "codec_service_0"; // 对外提供的服务名称
387           deviceMatchAttr = "hdf_codec_driver"; // 私有配置属性名称,通过此名称匹配对应的私有数据(包含寄存器配置)
388         }
389       }
390```
391
392**audio_config.hcs中配置私有依赖**
393
394配置audio_card设备依赖的Codec、Platform、Dai、Dsp之间的依赖关系。
395
396代码片段如下:
397
398```c
399root {
400    platform {
401        ...
402        controller_0x120c1001 :: card_controller {
403            // 配置私有数据属性名称,与device_info.hcs中的deviceMatchAttr对应
404            match_attr = "hdf_audio_driver_1";
405            serviceName = "hdf_audio_codec_primary_dev11"; // 对外提供的服务名称
406            codecName = "codec_service_1"; // codec服务名称
407            platformName = "dma_service_0"; // dma服务
408            cpuDaiName = "dai_service"; // CPU dai服务
409            codecDaiName = "tfa9879_codec_dai"; // codec dai服务
410            dspName = "dsp_service_0"; // dsp服务名称
411            dspDaiName = "dsp_dai"; // dsp dai
412        }
413    }
414}
415```
416
417**codec_config.hcs中配置私有寄存器**
418
419与配置在device_info.hcs中codec的deviceMatchAttr匹配,目前配置中包含寄存器配置。
420
421绑定控制功能配置主要是将控制功能及其寄存器参数按统一的结构规范,配置在HCS文件中并获取与解析后增加到控制链表中。
422
423- regConfig:寄存器与控制功能配置组名称。
424
425- ctrlParamsSeqConfig:控制功能寄存器配置组名称,其中item与controlsConfig组中的item位置顺序一一对应,表示某一功能对应的寄存器配置。
426
427- daiStartupSeqConfig:Dai启动配置配置组名称。
428
429- daiParamsSeqConfig:播放参数配置组名称。
430
431- resetSeqConfig:重置过程寄存器配置组名称。
432
433- initSeqConfig:初始化过程寄存器配置组名称。
434
435- controlsConfig:控制功能配置组名称,其中array index(具体业务场景)和iface(与HAL保持一致)为固定的值。
436
437- sapmConfig:电源管理控制功能配置组名称,其中array index(具体业务场景)和iface(与HAL保持一致)为固定的值。
438
439- ctrlSapmParamsSeqConfig:电源管理控制功能寄存器配置组名称。
440
441- sapmComponent:电源管理组件配置组名称。
442
443- array index:
444
445  controlsConfig配置组的array index是audio_codec_base.c文件中g_audioCodecControlsList数组的元素标号。
446
447  sapmConfig配置组的array index是audio_codec_base.c文件中g_audioSapmCfgNameList数组的元素标号。
448
449  sapmComponent配置组的compNameIndex是audio_codec_base.c文件中g_audioSapmCompNameList数组元素标号。
450
451- iface:虚拟混合器设备配置为2。
452
453```c
454 root {
455    platform {
456        template codec_controller {
457            match_attr = "";
458            serviceName = "";
459            codecDaiName = "";
460        }
461        controller_0x120c1030 :: codec_controller {
462            match_attr = "hdf_codec_driver";
463            serviceName = "codec_service_0";
464            codecDaiName = "codec_dai";
465
466            /* hi3516寄存器基地址 */
467            idInfo {
468                chipName = "hi3516";        // codec名字
469                chipIdRegister = 0x113c0000;  // codec基地址
470                chipIdSize = 0x1000;         // codec地址偏移
471            }
472
473           /* 寄存器配置,包含各种寄存器配置信息 */
474            regConfig {
475               /*   reg: register address
476                    rreg: register address
477                    shift: shift bits
478                    rshift: rshift bits
479                    min: min value
480                    max: max value
481                    mask: mask of value
482                    invert: enum InvertVal 0-uninvert 1-invert
483                    value: value
484                */
485
486                /* reg, value */
487                initSeqConfig = [
488                    0x14,    0x04000002,
489                    0x18,    0xFD200004,
490                    0x1C,    0x00180018,
491                    0x20,    0x83830028,
492                    0x24,    0x00005C5C,
493                    0x28,    0x00130000,
494                    0x30,    0xFF035A00,
495                    0x34,    0x08000001,
496                    0x38,    0x06062424,
497                    0x3C,    0x1E1EC001,
498                    0x14,    0x04000002
499                ];
500
501                /* control function config
502                    array index, iface, mixer/mux, enable, */
503                    0,  2,  0,  0,
504                    1,  2,  0,  1,
505                    2,  2,  0,  1,
506                    3,  2,  0,  1,
507                    4,  2,  0,  1,
508                    5,  2,  0,  1,
509                    8,  2,  0,  0,
510                    9,  2,  0,  0,
511                ];
512                /* control function register config
513                   reg, rreg, shift, rshift, min, max, mask, invert, value */
514                ctrlParamsSeqConfig = [
515                    0x3c, 0x3c, 24, 24, 0x0, 0x57, 0x7F, 1, 0,   // "Main Capture Volume"
516                    0x38, 0x38, 31, 31, 0x0, 0x1, 0x1, 0, 0,     // "Playback Mute"
517                    0x3c, 0x3c, 31, 31, 0x0, 0x1, 0x1, 0, 0,      // "Capture Mute"
518                    0x20, 0x20, 16, 16, 0x0, 0xF, 0x1F, 0, 0,     // "Mic Left Gain"
519                    0x20, 0x20, 24, 24, 0x0, 0xF, 0x1F, 0, 0,     // "Mic Right Gain"
520                    0x2000, 0x2000, 16, 16, 0x0, 0x7, 0x7, 0, 0,  // "Render Channel Mode"
521                    0x1000, 0x1000, 16, 16, 0x0, 0x7, 0x7, 0, 0  // "Capture Channel Mode"
522                ];
523
524                /* 上层下发参数后,写入音频相关信息的寄存器
525                   reg, rreg, shift, rshift, min, max, mask, invert, value */
526                daiParamsSeqConfig = [
527                    0x30, 0x30, 13, 13, 0x0, 0x1F, 0x1F, 0, 0x0,    // i2s_frequency
528                    0x1C, 0x1C, 6, 6, 0x0, 0x3, 0x3, 0, 0x0,       // adc_mode_sel
529                    0x30, 0x30, 22, 22, 0x0, 0x3, 0x3, 0, 0x0,     // i2s_datawith
530                ];
531
532                /* 电源管理功能寄存器配置
533                   reg, rreg, shift, rshift, min, max, mask, invert, value */
534                ctrlSapmParamsSeqConfig = [
535                    0x20, 0x20, 23, 23, 0x0, 0x1, 0x1, 0, 0,  // LPGA MIC 0 -- connect MIC
536                    0x20, 0x20, 31, 31, 0x0, 0x1, 0x1, 0, 0,  // RPGA MIC 0 -- connect MIC
537                    0x30, 0x30, 27, 27, 0x0, 0x1, 0x1, 0, 0,  // dacl to dacr mixer
538                    0x30, 0x30, 26, 26, 0x0, 0x1, 0x1, 0, 0  // dacr to dacl mixer
539                ];
540
541                /*
542                 电源管理组件配置
543                 sapmType, compNameIndex, reg, mask, shift, invert, kcontrolNews, kcontrolsNum
544                 reg = 0xFFFF: component has no sapm register bit
545                */
546                sapmComponent = [
547                    10, 0,    0x20,    0x1, 15,  1, 0, 0, // ADCL
548                    10, 1,    0x20,    0x1, 14,  1, 0, 0, // ADCR
549                    11, 2,    0x14,    0x1, 11,  1, 0, 0, // DACL
550                    11, 3,    0x14,    0x1, 12,  1, 0, 0, // DACR
551                    17, 4,    0x20,    0x1, 13,  1, 1, 1, // LPGA
552                    17, 5,    0x20,    0x1, 12,  1, 2, 1, // RPGA
553                    15, 6,  0xFFFF, 0xFFFF,  0,  0, 0, 0, // SPKL
554                    15, 7,  0xFFFF, 0xFFFF,  0,  0, 0, 0, // SPKR
555                    17, 52, 0xFFFF, 0xFFFF,  0,  0, 3, 1, // SPKL PGA
556                    17, 53, 0xFFFF, 0xFFFF,  0,  0, 4, 1, // SPKR PGA
557                    13, 40, 0xFFFF, 0xFFFF,  0,  0, 0, 0, // MIC1
558                    13, 41, 0xFFFF, 0xFFFF,  0,  0, 0, 0  // MIC2
559                ];
560
561              /* 电源管理功能配置
562                   array index, iface, mixer/mux, enable
563              */
564                sapmConfig = [
565                    0,    2,    0,    1,
566                    1,    2,    0,    1,
567                    2,    2,    0,    1,
568                    3,    2,    0,    1
569                ];
570            }
571        }
572    }
573}
574```
575
576在C代码中读取HCS配置文件来寄存器配置。
577
578```c
579static int32_t CodecDriverInit(struct HdfDeviceObject *device)
580{
581  ...
582  CodecGetConfigInfo(device, &g_codecData) ;
583  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
584  ...
585  return HDF_SUCCESS;
586}
587```
588
589Codec注册时入参device中已有controller_0x120c1030的节点信息,只需要解析其中的节点就可以获取配置信息。
590
591```c
592int32_t CodecGetConfigInfo(const struct HdfDeviceObject *device, struct CodecData *codecData)
593{
594  codecData->regConfig = (struct AudioRegCfgData *)OsalMemCalloc(sizeof(*(codecData->regConfig)));
595  CodecGetRegConfig(device, codecData->regConfig);
596  return HDF_SUCCESS;
597}
598```
599
600配置信息获取,配置节点。
601
602```c
603int32_t CodecGetRegConfig(const struct HdfDeviceObject *device, struct AudioRegCfgData *configData)
604{
605    ...
606    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
607    ...
608    idNode = drsOps->GetChildNode(root, "idInfo");
609    ParseAudioAttr(drsOps, idNode, &configData->audioIdInfo);
610    regCfgNode = drsOps->GetChildNode(root, "regConfig");
611    ...
612    DEV_RES_NODE_FOR_EACH_ATTR(regCfgNode, regAttr) {
613    ...
614    return HDF_SUCCESS;
615}
616```
617
618regConfig节点中子项的配置信息获取并使用。在框架进行配置文件解析后,可直接替换代码中的寄存器信息。
619
620```c
621int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
622{
623...
624    if (CodecRegDefaultInit(codec->devData->regCfgGroup) != HDF_SUCCESS) {
625        AUDIO_DRIVER_LOG_ERR("CodecRegDefaultInit failed.");
626        return HDF_FAILURE;
627    }
628...
629    return HDF_SUCCESS;
630}
631```
632
633### SmartPA驱动开发实例
634
635代码路径:device/board/hisilicon/hispark_taurus/audio_drivers/codec/tfa9879
636
637SmartPA归属于codec驱动的一种,其开发流程为:
638
6391. 定义填充一个具体的codec。
6402. 实现codec回调函数。
6413. 注册绑定到HDF框架。
6424. 配置HCS和Makefile。
643
644#### codec数据结构填充
645
646codec模块需要填充如下3个结构体:
647
648- g_tfa9879Data:codec设备操作函数集,其中包含HCS文件中的配置信息,且定义与映射了codec设备的初始化、读写寄存器的方法函数。
649
650- g_tfa9879DaiDeviceOps:codec设备DAI的数据集,其中定义与映射了codec设备DAI的操作集。
651
652- g_tfa9879DaiData:codec设备DAI的数据集,其中定义与映射了codec设备的数据访问接口的驱动名、初始化和操作集。
653
654```c
655struct CodecData g_tfa9879Data = {
656    .Init = Tfa9879DeviceInit,
657    .Read = CodecDeviceRegI2cRead,
658    .Write = CodecDeviceRegI2cWrite,
659};
660
661struct AudioDaiOps g_tfa9879DaiDeviceOps = {
662    .Startup = Tfa9879DaiStartup,
663    .HwParams = Tfa9879DaiHwParams,
664};
665
666struct DaiData g_tfa9879DaiData = {
667    .drvDaiName = "tfa9879_codec_dai",
668    .DaiInit = Tfa9879DaiDeviceInit,
669    .ops = &g_tfa9879DaiDeviceOps,
670    .Read = CodecDaiRegI2cRead,
671    .Write = CodecDaiRegI2cWrite,
672};
673```
674
675#### codecDevice和codecDai设备初始化
676
677设备初始化入口函数为Tfa9879DeviceInit,其中主要包括设置SmartPA I2C设备地址,获取配置数据、初始化(含重置)设备寄存器和绑定控制功能配置到控制链表中,当前Demo实现中也包括了Hi3516DV300设备的相关寄存器初始化,如初始化GPIO引脚等。
678
679```c
680int32_t Tfa9879DeviceInit(struct AudioCard *audioCard, const struct CodecDevice *device)
681{
682    int32_t ret;
683    ...
684    // 初始化GPIO引脚
685    ret = Hi35xxGpioPinInit();
686    ...
687    // 配置I2C参数
688    g_transferParam.i2cBusNumber = TFA9879_I2C_BUS_NUMBER;
689    g_transferParam.i2cDevAddr = TFA9879_I2C_DEV_ADDR;
690    g_transferParam.i2cRegDataLen = TFA9879_I2C_REG_DATA_LEN;
691    device->devData->privateParam = &g_transferParam;
692    ...
693    // 初始化设备寄存器
694    ret = CodecDeviceInitRegConfig(device);
695    ...
696    // 绑定功能控制配置
697    if (AudioAddControls(audioCard, device->devData->controls, device->devData->numControls) !=
698        HDF_SUCCESS) {
699        AUDIO_DRIVER_LOG_ERR("add controls failed.");
700        return HDF_FAILURE;
701    }
702    ...
703}
704```
705
706I2C读写寄存器公用函数:
707
708```c
709int32_t CodecDeviceRegI2cRead(const struct CodecDevice *codec, uint32_t reg, uint32_t *val)
710{
711    int32_t ret;
712    struct AudioAddrConfig regAttr;
713    struct I2cTransferParam *i2cTransferParam = NULL;
714    ...
715    i2cTransferParam = (struct I2cTransferParam *)codec->devData->privateParam;
716    ...
717    regAttr.addr = (uint8_t)reg;
718    regAttr.value = 0;
719    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, I2C_FLAG_READ);
720    ...
721    *val = regAttr.value;
722    return HDF_SUCCESS;
723}
724
725int32_t CodecDeviceRegI2cWrite(const struct CodecDevice *codec, uint32_t reg, uint32_t value)
726{
727    int32_t ret;
728    struct AudioAddrConfig regAttr;
729    struct I2cTransferParam *i2cTransferParam = NULL;
730    ...
731    i2cTransferParam = (struct I2cTransferParam *)codec->devData->privateParam;
732    ...
733    regAttr.addr = (uint8_t)reg;
734    regAttr.value = (uint16_t)value;
735    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, 0);
736    ...
737    return HDF_SUCCESS;
738}
739
740int32_t CodecDaiRegI2cRead(const struct DaiDevice *dai, uint32_t reg, uint32_t *value)
741{
742    ...
743    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, I2C_FLAG_READ);
744    ...
745    return HDF_SUCCESS;
746}
747
748int32_t CodecDaiRegI2cWrite(const struct DaiDevice *dai, uint32_t reg, uint32_t value)
749{
750    ...
751    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, 0);
752    ...
753    return HDF_SUCCESS;
754}
755```
756
757#### Codec操作函数集实现
758
759Tfa9879DaiStartup为启动时的一些设置,代码片段如下:
760
761```c
762int32_t Tfa9879DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
763{
764    int ret;
765    (void)card;
766    (void)device;
767    // 设置SmartPA的启动的寄存器配置
768    ret = CodecDaiDeviceStartupRegConfig(device);
769    ...
770    return HDF_SUCCESS;
771}
772
773```
774
775Tfa9879DaiHwParams为下发播放参数接口函数,代码片段如下:
776
777```c
778int32_t Tfa9879DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
779{
780    int32_t ret;
781    uint16_t frequency, bitWidth;
782    struct DaiParamsVal daiParamsVal;
783    (void)card;
784    ...
785    // 匹配采样率
786    ret = Tfa9879FrequencyParse(param->rate, &frequency);
787    ...
788    // 匹配位宽
789    ret = Tfa9879FormatParse(param->format, &bitWidth);
790    ...
791    daiParamsVal.frequencyVal = frequency;
792    daiParamsVal.formatVal = bitWidth;
793    daiParamsVal.channelVal = param->channels;  // 匹配声道
794    ret = Tfa9879DaiParamsUpdate(card->rtd->codecDai, daiParamsVal);
795    ...
796    return HDF_SUCCESS;
797}
798```
799
800#### Codec注册绑定到HDF
801
802此处依赖HDF框架的驱动实现方式,具体流程可参考[HDF驱动框架](driver-hdf-overview.md)。
803
804填充g_tfa9879DriverEntry结构体,moduleName与device_info.hcs中的moduleName匹配,实现Bind、Init、Release函数指针。
805
806device/board/hisilicon/hispark_taurus/audio_drivers/codec/tfa9879/src/tfa9879_accessory_adapter.c
807
808```c
809static int32_t Tfa9879DriverBind(struct HdfDeviceObject *device)
810{
811    (void)device;
812    AUDIO_DRIVER_LOG_INFO("success!");
813    return HDF_SUCCESS;
814}
815
816static int32_t Tfa9879DriverInit(struct HdfDeviceObject *device)
817{
818    int32_t ret;
819    ...
820    // 获取HCS中的配置数据
821    ret = CodecGetConfigInfo(device, &g_tfa9879Data);
822    ...
823    // 设置codec控制相关的接口函数和寄存器信息
824    ret = CodecSetConfigInfoOfControls(&g_tfa9879Data, &g_tfa9879DaiData);
825    ...
826    ret = CodecGetServiceName(device, &g_tfa9879Data.drvCodecName);
827    ...
828    ret = CodecGetDaiName(device, &g_tfa9879DaiData.drvDaiName);
829    ...
830    // 注册codec到声卡
831    ret = AudioRegisterCodec(device, &g_tfa9879Data, &g_tfa9879DaiData);
832    ....
833    return HDF_SUCCESS;
834}
835
836/* HdfDriverEntry definitions */
837struct HdfDriverEntry g_tfa9879DriverEntry = {
838    .moduleVersion = 1,
839    .moduleName = "CODEC_TFA9879",
840    .Bind = Tfa9879DriverBind,
841    .Init = Tfa9879DriverInit,
842    .Release = NULL,
843};
844HDF_INIT(g_tfa9879DriverEntry);
845```
846
847#### HCS配置流程
848
849配置过程可参考Codec驱动开发实例[HCS配置流程](#section4115)章节。
850
851### Platform驱动开发实例
852
853代码路径:device/board/hisilicon/hispark_taurus/audio_drivers/soc
854
855在Audio驱动开发中,platform为DMA驱动的适配。platform驱动开发主要包含如下几个重要步骤:
856
8571. 定义填充一个具体的platform
8582. 实现platform回调函数
8593. 注册绑定到HDF框架
8604. 配置HCS和Makefile
861
862#### Platform数据结构填充
863
864Platform模块需要填充如下2个结构体:
865
866- g_platformData :platform设备私有配置,其中包含platform设备的初始化和操作函数。
867
868- g_dmaDeviceOps :Dma设备操作函数集,包含了DMA一些通用接口的封装。
869
870```c
871struct AudioDmaOps g_dmaDeviceOps = {
872    .DmaBufAlloc = Hi3516DmaBufAlloc,             // dma内存申请函数接口
873    .DmaBufFree = Hi3516DmaBufFree,               // dma内存释放函数接口
874    .DmaRequestChannel = Hi3516DmaRequestChannel, // dma申请通道函数接口
875    .DmaConfigChannel = Hi3516DmaConfigChannel,   // dma通道配置函数接口
876    .DmaPrep = Hi3516DmaPrep,                     // dma准备函数接口
877    .DmaSubmit = Hi3516DmaSubmit,                 // dma submit函数接口
878    .DmaPending = Hi3516DmaPending,               // dma pending函数接口
879    .DmaPause = Hi3516DmaPause,                   // dma暂停、停止函数接口
880    .DmaResume = Hi3516DmaResume,                 // dma恢复函数接口
881    .DmaPointer = Hi3516DmaPointer,               // dma获取当前播放或录音位置函数接口
882};
883
884struct PlatformData g_platformData = {
885    .PlatformInit = AudioDmaDeviceInit, // dma设备初始化接口
886    .ops = &g_dmaDeviceOps,
887};
888```
889
890#### dmaDevice设备初始化
891
892设备初始化入口函数为AudioDmaDeviceInit,其中主要包括设置3516平台特有的AIAO初始化等。
893
894```c
895int32_t AudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platformDevice)
896{
897...
898    AiaoHalSysInit();
899    /* PIN MUX */
900    AiaoSysPinMux();
901    /* CLK reset */
902    AiaoClockReset();
903    /* aiao init */
904    AiaoDeviceInit(chnId);
905...
906    return HDF_SUCCESS;
907}
908```
909
910#### DMA操作函数集实现
911
912Dma设备操作函数集,包含了DMA通用接口的封装。如通用接口不能满足开发要求,可自行实现新的DMA回调函数。
913
914```c
915int32_t AudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platform);
916int32_t Hi3516DmaBufAlloc(struct PlatformData *data, const enum AudioStreamType streamType);
917int32_t Hi3516DmaBufFree(struct PlatformData *data, const enum AudioStreamType streamType);
918int32_t Hi3516DmaRequestChannel(const struct PlatformData *data, const enum AudioStreamType streamType);
919int32_t Hi3516DmaConfigChannel(const struct PlatformData *data, const enum AudioStreamType streamType);
920int32_t Hi3516DmaPrep(const struct PlatformData *data, const enum AudioStreamType streamType);
921int32_t Hi3516DmaSubmit(const struct PlatformData *data, const enum AudioStreamType streamType);
922int32_t Hi3516DmaPending(struct PlatformData *data, const enum AudioStreamType streamType);
923int32_t Hi3516DmaPause(struct PlatformData *data, const enum AudioStreamType streamType);
924int32_t Hi3516DmaResume(const struct PlatformData *data, const enum AudioStreamType streamType);
925int32_t Hi3516DmaPointer(struct PlatformData *data, const enum AudioStreamType streamType, uint32_t *pointer);
926```
927
928#### Platform注册绑定到HDF
929
930此处依赖HDF框架的驱动实现方式,具体流程可参考[HDF驱动框架](driver-hdf-overview.md)。
931
932- 填充g_platformDriverEntry结构体
933- moduleName与device_info.hcs中的moduleName匹配
934- 实现Bind、Init、Release函数指针
935
936device/board/hisilicon/hispark_taurus/audio_drivers/soc/src/hi3516_dma_adapter.c
937
938```c
939static int32_t Hi3516DmaDriverInit(struct HdfDeviceObject *device)
940{
941...
942    OsalMutexInit(&g_platformData.renderBufInfo.buffMutex);
943    OsalMutexInit(&g_platformData.captureBufInfo.buffMutex);
944    g_platformData.platformInitFlag = false;
945    ret = AudioSocRegisterPlatform(device, &g_platformData);
946...
947    return HDF_SUCCESS;
948}
949
950static void Hi3516DmaDriverRelease(struct HdfDeviceObject *device)
951{
952    struct PlatformHost *platformHost = NULL;
953...
954    platformHost = (struct PlatformHost *)device->service;
955...
956    OsalMutexDestroy(&g_platformData.renderBufInfo.buffMutex);
957    OsalMutexDestroy(&g_platformData.captureBufInfo.buffMutex);
958    OsalMemFree(platformHost);
959}
960
961/* HdfDriverEntry definitions */
962struct HdfDriverEntry g_platformDriverEntry = {
963    .moduleVersion = 1,
964    .moduleName = "DMA_HI3516",
965    .Bind = Hi3516DmaDriverBind,
966    .Init = Hi3516DmaDriverInit,
967    .Release = Hi3516DmaDriverRelease,
968};
969HDF_INIT(g_platformDriverEntry);
970```
971
972#### HCS配置流程
973
974配置过程可参考Codec驱动开发实例[HCS配置流程](#section4115)章节。
975
976### Dai驱动开发实例
977
978代码路径:device/board/hisilicon/hispark_taurus/audio_drivers/soc
979
980Dai驱动开发主要包含如下几个重要步骤:
981
9821. 定义填充一个具体的dai
9832. 实现dai回调函数
9843. 注册绑定到HDF框架
9854. 配置HCS和Makefile
986
987#### Dai数据结构填充
988
989Dai模块需要填充如下2个结构体:
990
991- g_daiData:dai设备私有配置,其中包含dai设备的初始化、读写寄存器、操作函数。
992
993- g_daiDeviceOps:dai设备操作函数集,包含了dai的参数设置、触发、启动。
994
995```c
996struct AudioDaiOps g_daiDeviceOps = {
997    .HwParams = DaiHwParams,
998    .Trigger = DaiTrigger,
999    .Startup = DaiStartup,
1000};
1001
1002struct DaiData g_daiData = {
1003    .DaiInit = DaiDeviceInit,
1004    .Read = AudioDeviceReadReg,
1005    .Write = AudioDeviceWriteReg,
1006    .ops = &g_daiDeviceOps,
1007};
1008```
1009
1010#### daiDevice设备初始化
1011
1012设备初始化入口函数为DaiDeviceInit,其中主要包括设置dai的配置信息初始化,添加到Controls等。
1013
1014```c
1015int32_t DaiDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai)
1016{
1017...
1018    struct DaiData *data = dai->devData;
1019    struct AudioRegCfgData *regConfig = dai->devData->regConfig;
1020...
1021    g_regCodecBase = OsalIoRemap(CODEC_REG_BASE, CODEC_MAX_REG_SIZE);
1022...
1023    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
1024    DaiSetConfigInfo(data);
1025    AudioAddControls(audioCard, data->controls, data->numControls);
1026    I2c6PinInit();
1027...
1028    data->daiInitFlag = true;
1029    return HDF_SUCCESS;
1030}
1031```
1032
1033#### Dai操作函数集实现
1034
1035AudioDeviceReadReg和AudioDeviceWriteReg在3516平台均未使用,作为接口预留。
1036
1037DaiHwParams中主要完成一些pcm流信息的设置。
1038
1039```c
1040int32_t DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
1041{
1042    uint32_t bitWidth;
1043    struct DaiDevice *device = card->rtd->cpuDai;
1044...
1045    DaiCheckSampleRate(param->rate);
1046    struct DaiData *data = DaiDataFromCard(card);
1047    data->pcmInfo.channels = param->channels;
1048...
1049    AudioFormatToBitWidth(param->format, &bitWidth);
1050...
1051    data->pcmInfo.bitWidth = bitWidth;
1052    data->pcmInfo.rate = param->rate;
1053    data->pcmInfo.streamType = param->streamType;
1054    data->regVirtualAddr = (uintptr_t)g_regDaiBase;
1055...
1056    DaiParamsUpdate(device);
1057    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
1058    return HDF_SUCCESS;
1059}
1060```
1061
1062DaiTrigger在3516平台也未使用,作为接口预留。
1063
1064DaiStartup为dai的启动函数,主要包括更新初始化寄存器配置、配置I2S等。
1065
1066```c
1067int32_t DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
1068{
1069    struct AudioMixerControl *regCfgItem = NULL;
1070...
1071    regCfgItem = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->regCfgItem;
1072    itemNum = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->itemNum;
1073
1074    device->devData->regVirtualAddr = (uintptr_t)g_regDaiBase;
1075    for (int i = 0; i < itemNum; i++) {
1076        int ret = AudioUpdateDaiRegBits(device, &regCfgItem[i], regCfgItem[i].value);
1077        if (ret != HDF_SUCCESS) {
1078            AUDIO_DRIVER_LOG_ERR("set frequency fail.");
1079            return HDF_FAILURE;
1080        }
1081    }
1082    device->devData->regVirtualAddr = (uintptr_t)g_regCodecBase;
1083
1084    if (I2sPinInit() != HDF_SUCCESS) {
1085        AUDIO_DRIVER_LOG_ERR("I2sPinInit fail.");
1086    }
1087
1088    return HDF_SUCCESS;
1089}
1090```
1091
1092#### Dai注册绑定到HDF
1093
1094此处依赖HDF框架的驱动实现方式,具体流程可参考[HDF驱动框架](driver-hdf-overview.md)。
1095
1096- 填充g_daiDriverEntry结构体
1097- moduleName与device_info.hcs中的moduleName匹配
1098- 实现Bind、Init、Release函数指针
1099
1100device/board/hisilicon/hispark_taurus/audio_drivers/soc/src/hi3516_dai_adapter.c
1101
1102```c
1103static int32_t DaiDriverBind(struct HdfDeviceObject *device)
1104{
1105...
1106    struct DaiHost *daiHost = (struct DaiHost *)OsalMemCalloc(sizeof(*daiHost));
1107...
1108    daiHost->device = device;
1109    device->service = &daiHost->service;
1110    g_daiData.daiInitFlag = false;
1111...
1112    return HDF_SUCCESS;
1113}
1114
1115static int32_t DaiDriverInit(struct HdfDeviceObject *device)
1116{
1117...
1118    DaiGetConfigInfo(device, &g_daiData);
1119    DaiGetServiceName(device);
1120...
1121    OsalMutexInit(&g_daiData.mutex);
1122    AudioSocRegisterDai(device, &g_daiData);
1123...
1124    return HDF_SUCCESS;
1125}
1126
1127static void DaiDriverRelease(struct HdfDeviceObject *device)
1128{
1129...
1130    OsalMutexDestroy(&g_daiData.mutex);
1131...
1132    struct DaiHost *daiHost = (struct DaiHost *)device->service;
1133...
1134    OsalMemFree(daiHost);
1135}
1136
1137/* HdfDriverEntry definitions */
1138struct HdfDriverEntry g_daiDriverEntry = {
1139    .moduleVersion = 1,
1140    .moduleName = "DAI_HI3516",
1141    .Bind = DaiDriverBind,
1142    .Init = DaiDriverInit,
1143    .Release = DaiDriverRelease,
1144};
1145HDF_INIT(g_daiDriverEntry);
1146```
1147
1148#### HCS配置流程
1149
1150配置过程可参考Codec驱动开发实例[HCS配置流程](#section4115)章节。
1151
1152### Makefile中添加编译配置
1153
1154添加新增文件到对应的Makefile中,将其编译链接到内核镜像。
1155
1156标准系统(linux):device/board/hisilicon/hispark_taurus/audio_drivers/Makefile
1157
1158```makefile
1159obj-$(CONFIG_DRIVERS_HDF_AUDIO_HI3516CODEC) += \
1160        codec/tfa9879/src/tfa9879_codec_adapter.o \
1161        codec/tfa9879/src/tfa9879_codec_ops.o \
1162        codec/hi3516/src/hi3516_codec_adapter.o \
1163        codec/hi3516/src/hi3516_codec_impl.o \
1164        codec/hi3516/src/hi3516_codec_ops.o \
1165        dsp/src/dsp_adapter.o \
1166        dsp/src/dsp_ops.o \
1167        soc/src/hi3516_dai_adapter.o \
1168        soc/src/hi3516_dai_ops.o \
1169        soc/src/hi3516_aiao_impl.o \
1170        soc/src/hi3516_dma_ops.o \
1171        soc/src/hi3516_dma_adapter.o
1172```
1173
1174小型系统(liteOS):drivers/adapter/khdf/liteos/model/audio/Makefile
1175
1176```makefile
1177LOCAL_SRCS += \
1178    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_adapter.c \
1179    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_ops.c \
1180    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_adapter.c \
1181    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_impl.c \
1182    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_ops.c \
1183    $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_adapter.c \
1184    $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_ops.c \
1185    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_adapter.c \
1186    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_ops.c \
1187    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_aiao_impl.c \
1188    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_ops.c \
1189    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_adapter.c
1190```
1191
1192### 源码结构与目录
1193
1194实现驱动接口头文件中的函数。以Hi3516为例,目录架构如下:
1195
1196驱动实现示例代码路径:device/board/hisilicon/hispark_taurus/audio_drivers/
1197
1198```shell
1199.
1200├── codec
1201│   ├── hi3516
1202│   │   ├── include
1203│   │   │   ├── hi3516_codec_impl.h
1204│   │   │   └── hi3516_codec_ops.h
1205│   │   └── src
1206│   │       ├── hi3516_codec_adapter.c    // codec驱动入口
1207│   │       ├── hi3516_codec_impl.c       // codec硬件相关操作实现
1208│   │       └── hi3516_codec_ops.c        // codec驱动函数接口实现
1209│   └── tfa9879
1210│       ├── include
1211│       │   └── tfa9879_codec_ops.h
1212│       └── src
1213│           ├── tfa9879_codec_adapter.c
1214│           └── tfa9879_codec_ops.c
1215├── dsp
1216│   ├── include
1217│   │   └── dsp_ops.h
1218│   └── src
1219│       ├── dsp_adapter.c                 // dsp驱动入口
1220│       └── dsp_ops.c
1221├── LICENSE
1222├── Makefile
1223└── soc
1224    ├── include
1225    │   ├── hi3516_aiao_impl.h
1226    │   ├── hi3516_dai_ops.h
1227    │   └── hi3516_dma_ops.h
1228    └── src
1229        ├── hi3516_aiao_impl.c
1230        ├── hi3516_dai_adapter.c          // dai驱动入口
1231        ├── hi3516_dai_ops.c
1232        ├── hi3516_dma_adapter.c          // dma驱动入口
1233        └── hi3516_dma_ops.c
1234```
1235
1236hcs文件与目录
1237
1238```shell
1239标准系统:
1240vendor/hisilicon/hispark_taurus_standard/
1241└── hdf_config
1242    └── khdf
1243        ├── audio
1244        │   ├── audio_config.hcs
1245        │   ├── codec_config.hcs
1246        │   ├── dai_config.hcs
1247        │   ├── dma_config.hcs
1248        │   └── dsp_config.hcs
1249        ├── device_info
1250        │   └── device_info.hcs
1251        └── hdf.hcs
1252
1253小型系统:
1254vendor/hisilicon/hispark_taurus/
1255├── config.json
1256└── hdf_config
1257    ├── audio
1258    │   ├── audio_config.hcs
1259    │   ├── codec_config.hcs
1260    │   ├── dai_config.hcs
1261    │   ├── dma_config.hcs
1262    │   └── dsp_config.hcs
1263    ├── device_info
1264    │   └── device_info.hcs
1265    └── hdf.hcs
1266```
1267
1268## 使用HAL的开发步骤与实例
1269
1270HAL(Hardware Abstraction Layer)的核心功能说明如下:
1271
12721. 提供Audio HDI接口供北向音频服务调用,实现音频服务的基本功能。
12732. 作为标准南向接口,保证南向OEM产商实现HDI-adapter的规范性,保证生态良性演进。
1274
1275代码路径:drivers/peripheral/audio/hal
1276
1277### HAL模块使用步骤
1278
1279![](figures/HAL流程图.png)
1280
12811. 使用入口函数GetAudioManagerFuncs()获取函数方法。
1282
12832. 获取所支持的声卡信息GetAllAdapters(),加载对应的声卡LoadAdapter()。
1284
12853. 创建播放类CreateRender()或者录音类,下发音频文件音频相关属性。
1286
12874. 调用创建好的播放类中挂载的方法调用render->control.Start()、render->RenderFrame()进行下发开始命令,音频数据循环下发。
1288
12895. 播放过程中可调用其他控制命令对播放业务进行控制操作,例如调节音量、暂停、静音等render->control.Pause()、render->control.Resume()、render->volume.SetVolume()。
1290
12916. 播放业务完成后,下发停止命令、销毁播放类、卸载声卡。
1292
1293    1. render->control.Stop();
1294
1295    2. adapter->DestroyRender();
1296
1297    3. manager->UnloadAdapter();
1298
1299### HAL使用实例
1300
1301```c
1302#include <string.h>
1303#include <stdio.h>
1304#include "audio_types.h"
1305#include <pthread.h>
1306#include "audio_manager.h"
1307
1308 /* so动态库引用打开 */
1309char *soPathHdi = "/system/lib/libhdi_audio.z.so";
1310void *g_handle = dlopen(soPathHdi , 1);
1311
1312int32_t FrameStart(void *param)
1313{
1314...
1315    /* 循环进行下发音频数据 */
1316    do {
1317        readSize = (remainingDataSize > bufferSize) ? bufferSize : remainingDataSize;
1318        numRead = fread(frame, 1, readSize, g_file);
1319        if (numRead > 0) {
1320            ret = render->RenderFrame(render, frame, numRead, &replyBytes);
1321            if (ret == HDF_ERR_INVALID_OBJECT) {
1322                LOG_FUN_ERR("Render already stop!");
1323                break;
1324            }
1325            remainingDataSize -= numRead;
1326        }
1327        /* 暂停等待函数 */
1328        while (g_waitSleep) {
1329            printf("music pause now.\n");
1330            pthread_cond_wait(&g_functionCond, &g_mutex);
1331            printf("music resume now.\n");
1332        }
1333    } while (!g_closeEnd && numRead > 0 && remainingDataSize > 0);
1334...
1335}
1336
1337static void *hal_main()
1338{
1339    /* 映射入口函数及调用 */
1340    struct AudioManager *(*getAudioManager)() =
1341    (struct AudioManager *(*)())(dlsym(g_handle, "GetAudioManagerFuncs"));
1342    struct AudioManager *manager = getAudioManager();
1343
1344    /* 获取声卡列表 */
1345    struct AudioAdapterDescriptor *descs = NULL;
1346    int32_t size = 0;
1347    int32_t ret = manager->GetAllAdapters(manager, &descs, &size);
1348
1349    /* 根据用户指定的声卡名称和端口描述进行匹配声卡及端口 */
1350    enum AudioPortDirection port = PORT_OUT;  // 端口类型为OUT,放音
1351    struct AudioPort renderPort;
1352    char * adapterNameCase = "primary";
1353    int32_t index = SwitchAdapter(descs, adapterNameCase, port, &renderPort, size);
1354
1355    /* 根据匹配到的声卡信息进行加载声卡 */
1356    struct AudioAdapter *adapter = NULL;
1357    struct AudioAdapterDescriptor *desc = &descs[index];  // 根据匹配到的声卡信息获取对应设备
1358    manager->LoadAdapter(manager, desc, &adapter);   // 加载声卡,获取声卡方法实例
1359
1360    /* 创建播放类 */
1361    struct AudioRender *render;
1362    struct AudioDeviceDescriptor devDesc;
1363    struct AudioSampleAttributes attrs;
1364    InitDevDesc(&devDesc, renderPort.portId);  // 初始化设置设备参数
1365    WavHeadAnalysis(g_file, &attrs);  // 解析音频文件设置Attributes
1366    adapter->CreateRender(adapter, &devDesc, &attrs, &render);
1367
1368    /* 下发音频数播放 */
1369    render->control.Start((AudioHandle)render);   // 下发控制命令start,准备动作
1370    pthread_create(&g_tids, NULL, (void *)(&FrameStart), &g_str); // 拉起线程进行播放
1371
1372    /* 控制命令 */
1373    render->control.Pause((AudioHandle)render);  // 下发暂停操作
1374    render->control.Resume((AudioHandle)render); // 下发恢复操作
1375    render->volume.SetVolume((AudioHandle)render, 0.5); // 设置音量
1376
1377     /* 停止播放,销毁播放类 */
1378    render->control.Stop((AudioHandle)render);
1379    adapter->DestroyRender(adapter, render);
1380     /* 卸载声卡 */
1381    manager->UnloadAdapter(manager, adapter);
1382}
1383```
1384
1385
1386
1387## 总结
1388
1389以上就是基于Audio驱动框架进行移植开发过程中,所涉及的所有关键适配点。重点介绍了 Audio驱动适配方法、HDI层接口使用方法。开发者可以根据不同芯片进行适配,方便简单。希望通过本次的文档,您能初步掌握基于HDF框架的Audio驱动开发。
1390