1# Audio 2 3 4## Audio Driver Overview 5 6A multimedia system is an indispensable part in Internet of Things (IoT) devices. Audio is an important module of the multimedia system, and building an audio driver model is particularly important in device development. 7 8This document describes the audio driver architecture and functional modules and how to develop audio drivers based on the Hardware Driver Foundation (HDF). You can develop your own drivers and call Hardware Abstraction Layer (HAL) APIs based on this driver architecture. 9 10 11 12## Audio Driver Architecture 13 14The audio driver framework is implemented based on the [HDF](driver-overview-foundation.md). The following figure illustrates the audio driver architecture. 15 16 17 18The driver architecture consists of the following: 19- Hardware Device Interface (HDI) adapter: implements the audio HAL driver (for HDI adaptation) and provides hardware driver APIs for audio services (frameworks). The HDI adapter provides API objects such as **AudioManager**, **AudioAdapter**, **AudioControl**, **AudioCapture**, and **AudioRender**. 20- Audio Interface Lib: works with the Audio Driver Model (ADM) in the kernel to control audio hardware, read recording data, and write playback data. The **Stream_ctrl_common** in the Audio Interface Lib interacts with the Audio HDI Adapter layer. 21- ADM: helps system developers to develop scenario-specific applications for the multimedia audio subsystem. With the ADM, codec and DSP device vendors can adapt their driver code based on the APIs provided by the ADM and implement quick development and easy adaptation to the OpenHarmony system. 22- Audio Control Dispatch: dispatches the control instructions from the Audio Interface Lib to the driver layer. 23- Audio Stream Dispatch: dispatches the data from the Audio Interface Lib to the driver layer. 24 25- Card Manager: manages multiple audio adapters. Each audio adapter consists of the digital audio interface (DAI), platform, codec, DSP, and Smart Audio Power Manager (SAPM) modules. 26- Platform Drivers: driver adaptation layer. 27- SAPM: optimizes the power consumption policy of the ADM. 28 29## Audio Driver Development 30 31The following uses the Hi3516D V300 as an example to describe how to develop drivers based on the audio driver architecture. 32 33### Audio ADM Architecture 34 35The audio driver provides the **hdf_audio_render**, **hdf_audio_capture**, and **hdf_audio_control** services for the HDI layer. The driver service nodes in the **dev** directory of the development board are as follows: 36 37```shell 38# ls -l hdf_audio* 39crw-rw---- 1 system system 247, 6 1970-01-01 00:00 hdf_audio_capture // Voice recording service. 40crw-rw---- 1 root root 247, 4 1970-01-01 00:00 hdf_audio_codec_primary_dev0 // Audio adapter device 0. 41crw-rw---- 1 root root 247, 4 1970-01-01 00:00 hdf_audio_codec_primary_dev11 // Audio adapter device 1. 42crw-rw---- 1 system system 247, 5 1970-01-01 00:00 hdf_audio_control // Audio control service. 43crw-rw---- 1 system system 247, 7 1970-01-01 00:00 hdf_audio_render // Audio playback service. 44``` 45 46The audio adapters have the following driver services: 47 48hdf_audio_codec_primary_dev0 49 50- **dma_service_0**: DMA service 51- **dai_service**: CPU DAI service 52- **codec_service_0**: codec service (which can be smartPA) 53- **dsp_service_0**: DSP service (optional) 54 55hdf_audio_codec_primary_dev11 56 57- **dma_service_0**: DMA service 58- **dai_service**: CPU DAI service 59- **codec_service_1**: codec service (which can be smartPA) 60- **dsp_service_0**: DSP service (optional) 61 62#### Startup Process 63 64 65 661. When the system starts, the platform, codec, DSP, and DAI drivers of the audio module are loaded first. Each driver obtains the configuration information from its configuration file and saves the obtained information to the data structs. 67 682. Each driver module calls the ADM registration interface to add itself to the linked list of the driver module. 69 703. The ADM obtains the hdf_audio_driver_0 and hdf_audio_driver_1 configuration and loads the devices of each module. 71 724. The ADM module initializes each module device by calling the initialization API of the respective module. 73 745. The initialized audio devices are added to the cardManager linked list. 75 76#### Playback Process 77 78 79 801. The Audio Interface Lib sends the **Render Open** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to deliver the instruction. 81 822. The Audio Interface Lib sends a path select instruction to the Control Dispatch service. The Control Dispatch service calls the DAI API to set the path. 83 843. The Audio Interface Lib sends hardware parameters to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to set the hardware parameters. 85 864. The Audio Interface Lib sends the start playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to perform related settings for each module. 87 885. The Audio Interface Lib sends audio data to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioPcmWrite** API to send the audio data to DMA. 89 906. The Audio Interface Lib sends the stop playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the stop API of each module to perform related stop settings for each module. 91 927. The Audio Interface Lib sends the **Render Close** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioRenderClose** API to release resources. 93 94#### Control Process 95 96 97 981. When the volume needs to be adjusted, the Audio Interface Lib sends an instruction for obtaining the volume range to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **get()** of the codec module to obtain the volume range. 992. The Audio Interface Lib sends an instruction for setting the volume to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **Set()** of the codec module to set the volume. 100 101### Common Audio Driver Functions 102 103| Function | Description | 104| ------------------------------ | ------------------------------------------- | 105| CodecDeviceReadReg | Reads data from a codec register. | 106| CodecDeviceWriteReg | Writes data to a codec register. | 107| CodecDaiRegI2cRead | Reads data from a codec register over an I2C interface to a codec DAI. | 108| CodecDaiRegI2cWrite | Writes data to a codec register over an I2C interface from a codec DAI. | 109| CodecDeviceRegI2cRead | Reads data from a codec register over an I2C interface to a codec device. | 110| CodecDeviceRegI2cWrite | Write data to a codec register over an I2C interface from a codec device. | 111| CodecDeviceInitRegConfig | Initializes codec. | 112| CodecDaiDeviceStartupRegConfig | Starts a codec device. | 113| CodecSetCtlFunc | Sets the **set()** and **get()** functions. | 114| CodecSetConfigInfoOfControls | Sets the codec control function and register information.| 115| CodecGetConfigInfo | Obtains the code HDF configuration source (HCS). | 116| CodecGetDaiName | Obtains the DAI name in the HCS. | 117| CodecGetServiceName | Obtains the service name in the HCS. | 118| DaiDeviceReadReg | Reads data from a DAI register. | 119| DaiDeviceWriteReg | Writes data to a DAI register. | 120| DaiSetConfigInfoOfControls | Sets the DAI control function and register information. | 121| DaiGetConfigInfo | Obtains the DAI HCS. | 122 123 124 125### Audio Driver Development Procedure 126 127#### Development on an Adapted Platform 128 129The following figure shows the process for developing the codec or SmartPA driver on a chip platform (Hi3516D V300) to which the ADM has adapted. 130 131 132 133- Add register information to the private HDF configuration source (HCS) of the codec or SmartPA based on the chip description. 134 135- If the workflow of the newly added codec or SmartPA is the same as that of the existing codec or SmartPA, you do not need to implement the operation function set or configure the compilation file for the newly added codec or SmartPA. 136 137- Perform build, debugging, and testing. 138 139#### Development on a New Platform 140 141The following figure shows the driver development process if the ADM has not adapted to the platform. 142 143 144 145The codec (optional), DAI, DMA, DSP (optional), and SmartPA (optional) modules of the audio adapter need to be adapted to the new platform. 146 147- Add register information of each module driver to the private configuration file of the respective module according to the chip description. 148 149- Implement the operation function set of each module. 150 151- Modify the compilation file of the audio module. 152 153- Perform build, debugging, and testing. 154 155## Audio Driver Development Examples 156 157Code path: **device/board/hisilicon/hispark_taurus/audio_drivers** 158 159The following uses Hi3516D V300 as an example to describe how to develop the codec driver, DAI driver, and Platform driver. 160 161### Codec Driver Development Example 162 163Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/codec/hi3516** 164 165The major steps for developing the codec driver are as follows: 166 1671. Define and fill in a codec instance. 1682. Implement callbacks for the codec instance. 1693. Register and bind the codec instance to the HDF. 1704. Configure the HCS and makefile. 171 172#### Filling in Codec Data Structs 173 174Fill in the following data structs for the codec module: 175 176- **g_codecData**: operation function set and private data set of the codec device. 177 178- **g_codecDaiDeviceOps**: codec DAI device operation function set, including APIs for starting transmission and setting parameters. 179 180- **g_codecDaiData**: operation function set and private data set of the digital audio interface of the codec. 181 182```c 183struct CodecData g_codecData = { 184 .Init = CodecDeviceInit, // Initialize the codec device (need to be implemented for a new platform). 185 .Read = AudioDeviceReadReg, // Read the register (available in the existing framework). 186 .Write = AudioDeviceWriteReg, // Write the register (available in the existing framework). 187}; 188 189struct AudioDaiOps g_codecDaiDeviceOps = { 190 .Startup = CodecDaiStartup, // Start transmission (need to be implemented for a new platform). 191 .HwParams = CodecDaiHwParams, // Set parameters (need to be implemented for a new platform). 192}; 193 194struct DaiData g_codecDaiData = { 195 .DaiInit = CodecDaiDeviceInit,// Initialize the codec DAI device (need to be implemented for a new platform). 196 .ops = &g_codecDaiDeviceOps, // Codec DAI device operation function set. 197}; 198``` 199 200#### Initializing codecDevice and codecDai 201 202**CODECDeviceInit** sets audio input/audio output (AIAO), initializes registers, inserts **g_audioControls** into the controller linked list, initializes the power management, and selects a path. 203 204```c 205int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec) 206{ 207 ... 208 /* Register set() and get() of the AIAO module on the Hi3516. */ 209 CodecSetCtlFunc(codec->devData, AudioCodecAiaoGetCtrlOps, AudioCodecAiaoSetCtrlOps) 210 ... 211 /* Hi3516 codec register IoRemap. */ 212 CodecHalSysInit(); 213 ... 214 /* Initialize the codec registers of the Hi3516. */ 215 CodecRegDefaultInit(codec->devData->regCfgGroup); 216 ... 217 /* Add g_audioControls of the Hi3516 to the controller linked list.*/ 218 AudioAddControls(audioCard, codec->devData->controls, codec->devData->numControls); 219 ... 220 /* Load the codec of the Hi3516 to the SAPM. */ 221 AudioSapmNewComponents(audioCard, codec->devData->sapmComponents, codec->devData->numSapmComponent); 222 ... 223 /* Add the codec of the Hi3516 to the audioRoutes linked list. */ 224 AudioSapmAddRoutes(audioCard, g_audioRoutes, HDF_ARRAY_SIZE(g_audioRoutes); 225 ... 226 AudioSapmNewControls(audioCard); 227 ... 228 /* Hi3516 codec power management. */ 229 AudioSapmSleep(audioCard); 230 ... 231 return HDF_SUCCESS; 232} 233``` 234 235**CodecDaiDeviceInit** initializes the codec DAI device. This API is not used on the Hi3516 and is reserved. 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#### Implementing the Codec Operation Function Set 249 250The codec module is encapsulated with the **read()** and **write()** functions of the read and write registers at the operating system abstraction layer (OSAL). 251 252If the new platform cannot use the OSAL **read()** and **write()** functions to operate registers, you should implement them. 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 269**CodecDaiStartup** completes startup settings. 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 283**CodecDaiHwParams** sets parameters, including the sampling rate and bit width. 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#### Registering and Binding Codec to HDF 302 303The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md). 304 305Fill in the **g_codecDriverEntry** struct. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions. 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 320**CodecDriverBind** binds the device in the HDF to the codec and registers the codec service with the 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 333**CodecDriverInit** obtains the **codecService** name and private register configuration, and inserts them into the linked list by using **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 349**CodecDriverRelease** releases driver resources. 350 351```c 352static void CodecDriverRelease(struct HdfDeviceObject *device) 353{ 354 codecHost = (struct CodecHost *)device->service; 355 OsalMemFree(codecHost); 356} 357``` 358 359#### Configuring HCS 360 361Configure the driver node, loading sequence, and service name in the .hcs file. For details about the HCS syntax, see [Configuration Management](driver-hdf-manage.md) of the HDF. 362 363Path of the standard-system configuration file: 364 365**vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/** 366 367Path of the small-system configuration file: 368 369**vendor/hisilicon/hispark_taurus/hdf_config/** 370 371**Configuring Codec Device Information in device_info.hcs** 372 373Add codec node configuration. Modify **moduleName** in the configuration file. The value must be the same as **moduleName** in the **HdfDriverEntry** struct. Generally, the value should present the hardware platform. For example, moduleName = "CODEC_HI3516". 374 375The code snippet is as follows: 376 377```c 378 audio :: host { 379 device_codec :: device { 380 device0 :: deviceNode { 381 policy = 1; // The codec module provides services only for the kernel. 382 priority = 50; // The codec module must be loaded before the load of the HDF_AUDIO module. 383 preload = 0; 384 permission = 0666; 385 moduleName = "CODEC_HI3516"; // The value must be the same as moduleName in HdfDriverEntry. 386 serviceName = "codec_service_0"; // Name of the service provided externally. 387 deviceMatchAttr = "hdf_codec_driver"; // Name of the private attribute, which is used to match the corresponding private data (including the register configuration). 388 } 389 } 390``` 391 392**Configuring Dependencies in audio_config.hcs** 393 394Configure the dependency between the codec, platform, DAI, and DSP on which the audio_card device depends. 395 396The code snippet is as follows: 397 398```c 399root { 400 platform { 401 ... 402 controller_0x120c1001 :: card_controller { 403 // Set the private data attribute name, which must be the same as the deviceMatchAttr in device_info.hcs. 404 match_attr = "hdf_audio_driver_1"; 405 serviceName = "hdf_audio_codec_primary_dev11"; // Name of the service provided externally. 406 codecName = "codec_service_1"; // Codec service name. 407 platformName = "dma_service_0"; // DMA service. 408 cpuDaiName = "dai_service"; // CPU DAI service. 409 codecDaiName = "tfa9879_codec_dai"; // Codec DAI service. 410 dspName = "dsp_service_0"; // DSP service name. 411 dspDaiName = "dsp_dai"; // DSP DAI. 412 } 413 } 414} 415``` 416 417**Configuring Private Registers in codec_config.hcs** 418 419The configuration matches **deviceMatchAttr** of the codec configured in **device_info.hcs**. It includes the register configuration. 420 421Binding the control functionality configuration is to configure the control functionalities and their register parameters in the .hcs file according to unified struct specifications. The configuration can be obtained and parsed, and added to the controller linked list. 422 423- **regConfig**: register and control functionality configuration. 424 425- **ctrlParamsSeqConfig**: register configuration for a function. The items in **ctrlParamsSeqConfig** must be in the same sequence as the items in **controlsConfig**. 426 427- **daiStartupSeqConfig**: DAI startup configuration. 428 429- **daiParamsSeqConfig**: playback parameter configuration. 430 431- **resetSeqConfig**: reset process register configuration. 432 433- **initSeqConfig**: initialization process register configuration. 434 435- **controlsConfig**: control function configuration. The **array index** (specific service scenario) and **iface** (same as that in the HAL) have fixed values. 436 437- **sapmConfig**: power management and control function configuration. The values of **array index** (specific service scenario) and **iface** (consistent with the HAL) have fixed values. 438 439- **ctrlSapmParamsSeqConfig**: register configuration of the power management and control function. 440 441- **sapmComponent**: power management component configuration. 442 443- **array index**: 444 445 The **array index** in **controlsConfig** is the element ID in the **g_audioCodecControlsList** array in the **audio_codec_base.c** file. 446 447 The **array index** in **sapmConfig** is the element ID in the **g_audioSapmCfgNameList** array in the **audio_codec_base.c** file. 448 449 The **compNameIndex** in **sapmComponent** is the element ID in the **g_audioSapmCompNameList** array in the **audio_codec_base.c** file. 450 451- **iface**: **2** for the virtual mixer device. 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 /* Base address of Hi3516 registers. */ 467 idInfo { 468 chipName = "hi3516"; // Codec name. 469 chipIdRegister = 0x113c0000; // Codec base address. 470 chipIdSize = 0x1000; // Codec address offset. 471 } 472 473 /* Register configuration, including configuration of registers. */ 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 functionality configuration. 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 functionality register configuration 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 /* After the upper layer delivers parameters, write audio-related data to registers. 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 /* Configuration of the power management function register. 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 Power management component configuration. 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 /* Power management function configuration. 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 576Read the .hcs files in the C code to obtain register configuration. 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 589When the codec is registered, the input parameter **device** contains controller_0x120c1030 node information. You only need to parse the node to obtain the configuration information. 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 600Obtain the node configuration to configure the node. 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 618Obtain and use the configuration of the **regConfig** node. After the configuration files are parsed, the register information in the code can be directly updated. 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 Driver Development Example 634 635Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/codec/tfa9879** 636 637The SmartPA is a type of codec driver. The development process is as follows: 638 6391. Define and fill in a codec instance. 6402. Implement callbacks for the codec instance. 6413. Register and bind the codec instance to the HDF. 6424. Configure the HCS and makefile. 643 644#### Filling in the Codec Data Structs 645 646Fill in the following data structs for the codec module: 647 648- **g_tfa9879Data**: operation function set of the codec device. It contains the configuration in the .hcs file, and defines and maps the functions for initializing the codec device and reading and writing registers. 649 650- **g_tfa9879DaiDeviceOps**: DAI data set that defines and maps the operations of the codec device DAI. 651 652- **g_tfa9879DaiData**: DAI data set that defines and maps the driver name, initialization, and operations of the data access interfaces of the codec device. 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#### Initializing codecDevice and codecDai 676 677As the entry function for device initialization, **Tfa9879DeviceInit** sets the address of the SmartPA I2C device, obtains configuration data, initializes (including resets) the device registers, and adds the control functionality to the controller linked list. The current demo also includes the initialization of the registers related to the Hi3516D V300 device, such as initialization of GPIO pins. 678 679```c 680int32_t Tfa9879DeviceInit(struct AudioCard *audioCard, const struct CodecDevice *device) 681{ 682 int32_t ret; 683 ... 684 // Initialize GPIO pins. 685 ret = Hi35xxGpioPinInit(); 686 ... 687 // Set I2C parameters. 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 // Initialize device registers. 694 ret = CodecDeviceInitRegConfig(device); 695 ... 696 // Bind the control functionality configuration. 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 706Common functions of the I2C read/write registers: 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, ®Attr, 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, ®Attr, 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, ®Attr, 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, ®Attr, 0); 752 ... 753 return HDF_SUCCESS; 754} 755``` 756 757#### Implementing the Codec Operation Function Set 758 759**Tfa9879DaiStartup** performs startup settings. The code snippet is as follows: 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 // Set the register for starting the SmartPA. 768 ret = CodecDaiDeviceStartupRegConfig(device); 769 ... 770 return HDF_SUCCESS; 771} 772 773``` 774 775**Tfa9879DaiHwParams** delivers playback parameters. The code snippet is as follows: 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 // Set the sampling rate. 786 ret = Tfa9879FrequencyParse(param->rate, &frequency); 787 ... 788 // Set the bit width. 789 ret = Tfa9879FormatParse(param->format, &bitWidth); 790 ... 791 daiParamsVal.frequencyVal = frequency; 792 daiParamsVal.formatVal = bitWidth; 793 daiParamsVal.channelVal = param->channels; // Set the audio channel. 794 ret = Tfa9879DaiParamsUpdate(card->rtd->codecDai, daiParamsVal); 795 ... 796 return HDF_SUCCESS; 797} 798``` 799 800#### Registering and Binding Codec to HDF 801 802The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md). 803 804Fill in the **g_tfa9879DriverEntry** struct. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions. 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 // Obtain configuration data from .hcs files. 821 ret = CodecGetConfigInfo(device, &g_tfa9879Data); 822 ... 823 // Set the interface functions and register information related to codec control. 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 // Register the codec with the audio adapter. 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#### Configuring HCS 848 849For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**. 850 851### Platform Driver Development Example 852 853Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/soc** 854 855In audio driver development, the Platform module is configured to adapt to the DMA driver. The major steps for developing the platform driver are as follows: 856 8571. Define and fill in a platform instance. 8582. Implement callbacks for the platform instance. 8593. Register and bind the codec instance to the HDF. 8604. Configure the HCS and makefile. 861 862#### Filling in Platform Data Structures 863 864Fill in the following structs for the platform module: 865 866- **g_platformData**: private configuration of the platform device, including the initialization and operation functions of the platform device. 867 868- **g_dmaDeviceOps**: DMA device operation function set, including the encapsulation of some common DMA APIs. 869 870```c 871struct AudioDmaOps g_dmaDeviceOps = { 872 .DmaBufAlloc = Hi3516DmaBufAlloc, // Apply for memory for the DMA device. 873 .DmaBufFree = Hi3516DmaBufFree, // Release the memory of the DMA device. 874 .DmaRequestChannel = Hi3516DmaRequestChannel, // Request a DMA channel. 875 .DmaConfigChannel = Hi3516DmaConfigChannel, // Configure the DMA channel. 876 .DmaPrep = Hi3516DmaPrep, // Prepare for DMA. 877 .DmaSubmit = Hi3516DmaSubmit, // Submit a DMA request. 878 .DmaPending = Hi3516DmaPending, // Pend DMA. 879 .DmaPause = Hi3516DmaPause, // Pause or stop the DMA service. 880 .DmaResume = Hi3516DmaResume, // Resume the DMA service. 881 .DmaPointer = Hi3516DmaPointer, // Obtain the current playing or recording position. 882}; 883 884struct PlatformData g_platformData = { 885 .PlatformInit = AudioDmaDeviceInit, // Initialize the DMA device. 886 .ops = &g_dmaDeviceOps, 887}; 888``` 889 890#### Initializing dmaDevice 891 892**AudioDmaDeviceInit** initializes the DMA device, including setting the Hi3516 AIAO module. 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 initialization */ 904 AiaoDeviceInit(chnId); 905... 906 return HDF_SUCCESS; 907} 908``` 909 910#### Implementing the DMA Operation Function Set 911 912The DMA device operation function set includes the encapsulation of DMA common APIs. If the common APIs cannot meet development requirements, you can implement new DMA callbacks. 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#### Registering and Binding Platform to HDF 929 930The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md). 931 932- Fill in the **g_platformDriverEntry** struct. 933- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. 934- Implement the pointers to the **Bind**, **Init**, and **Release** functions. 935 936**device/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#### Configuring HCS 973 974For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**. 975 976### DAI Driver Development Example 977 978Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/soc** 979 980The major steps for developing the DAI driver are as follows: 981 9821. Define and fill in a DAI instance. 9832. Implement callbacks for the DAI instance. 9843. Register and bind the codec instance to the HDF. 9854. Configure the HCS and makefile. 986 987#### Filling in DAI Data Structures 988 989Fill in the following structs for the DAI module: 990 991- **g_daiData**: private configuration of the DAI device, including the initialization of the DAI device, read/write of registers, and operation functions. 992 993- **g_daiDeviceOps**: DAI device operation function set, including setting DAI parameters and triggering and starting the DAI device. 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#### Initializing daiDevice 1011 1012**DaiDeviceInit** initializes DAI configuration and adds the information to the controller linked list. 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#### Implementing the DAI Operation Function Set 1034 1035**AudioDeviceReadReg** and **AudioDeviceWriteReg** are not used on the Hi3516 and are reserved. 1036 1037**DaiHwParams** sets PCM stream information. 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 1062**DaiTrigger** is not used on the Hi3516 and is reserved. 1063 1064**DaiStartup** updates the register configuration and configures the 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, ®CfgItem[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#### Registering and Binding DAI to HDF 1093 1094The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md). 1095 1096- Fill in the **g_daiDriverEntry** struct. 1097- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. 1098- Implement the pointers to the **Bind**, **Init**, and **Release** functions. 1099 1100**device/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#### Configuring HCS 1149 1150For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**. 1151 1152### Adding Compilation Configuration to Makefile 1153 1154Add the newly added files to the **Makefile** file to link them to the kernel image. 1155 1156Standard system (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 1174Small system (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### Source Code Structure and Directory 1193 1194The development example implements the functions in the header file of the driver interface. The following uses Hi3516 as an example to describe the directory struct. 1195 1196Path of the driver implementation sample code: **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 driver entry 1207│ │ │ ├── hi3516_codec_impl.c // Implementation of codec hardware operations 1208│ │ │ └── hi3516_codec_ops.c // Implementation of codec driver APIs 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 driver entry 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 driver entry 1231 ├── hi3516_dai_ops.c 1232 ├── hi3516_dma_adapter.c // DMA driver entry 1233 └── hi3516_dma_ops.c 1234``` 1235 1236HCS Files and Directory 1237 1238```shell 1239Standard system: 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 1253Small system: 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-based Development Procedure and Example 1269 1270The Hardware Abstraction Layer (HAL) provides the following function: 1271 1272- Provides audio HDIs for audio services to implement basic audio features on applications. 1273- Provides standard interfaces for device developers to comply with the HDI adapter standards. This promises a healthy evolution of the ecosystem. 1274 1275Code path: **drivers_interface/audio/v1_0** 1276 1277### Development procedure 1278 1279 1280 12811. Call **GetAudioManagerFuncs()** to obtain methods. 1282 12832. Use **GetAllAdapters()** to obtain information about the supported audio adapter, and call **LoadAdapter()** to load the audio adapter. 1284 12853. Create a **Render** class by calling **CreateRender()** or create a recorder class and deliver audio attributes. 1286 12874. Call the methods hooked in the **Render** class created. For example, call **render->Start()** to start the playback, and call **render->RenderFrame()** to deliver audio data cyclically. 1288 12895. During the playback, call control commands to control the playback service, for example, call **render->SetVolume()** to adjust the volume, call **render->Pause()** to pause the playback, and call **render->Resume()** to resume the playback. 1290 12916. After the playback is complete, call **render->Stop()** to stop the playback, call **adapter->DestroyRender()** to destroy the playback instance, and call **audioManagerIns->UnloadAdapter()** to unload the audio adapter. 1292 1293### HAL Usage Example 1294 1295```c 1296#include <string.h> 1297#include <stdio.h> 1298#include <pthread.h> 1299#include "v1_0/audio_types.h" 1300#include "v1_0/iaudio_manager.h" 1301 1302struct IAudioRender *g_render = NULL; 1303struct IAudioAdapter *g_adapter = NULL; 1304struct AudioDeviceDescriptor g_devDesc; 1305struct AudioSampleAttributes g_attrs; 1306struct AudioHeadInfo g_wavHeadInfo; 1307bool g_isDirect = false; //IPC Loading 1308uint32_t g_renderId = 0; 1309 1310static int32_t FrameStart(const struct StrPara *param) 1311{ 1312... 1313 /* Initialize parameters. */ 1314 char *frame = param->frame; 1315 int32_t bufferSize = param->bufferSize; 1316 size_t remainingDataSize = g_wavHeadInfo.riffSize; 1317 1318 /* Send audio data cyclically. */ 1319 do { 1320 uint64_t replyBytes = 0; 1321 size_t readSize = (remainingDataSize > bufferSize) ? (size_t)bufferSize : remainingDataSize; 1322 numRead = fread(frame, 1, readSize, g_file); 1323 if (numRead > 0) { 1324 int32_t ret = render->RenderFrame(render, (int8_t *)frame, numRead, &replyBytes); 1325 if (ret == HDF_ERR_INVALID_OBJECT) { 1326 AUDIO_FUNC_LOGE("Render already stop!"); 1327 break; 1328 } 1329 remainingDataSize -= numRead; 1330 } 1331 /* Pause the playback and wait. */ 1332 while (g_waitSleep) { 1333 printf("music pause now.\n"); 1334 pthread_cond_wait(&g_functionCond, &g_mutex); 1335 printf("music resume now.\n"); 1336 } 1337 } while (!g_closeEnd && numRead > 0 && remainingDataSize > 0); 1338... 1339} 1340 1341static void *hal_main() 1342{ 1343 int32_t adapterIndex = 0; 1344 struct AudioPort *renderPort; 1345 1346 /* Call IAudioManagerGet() to obtain the entry function. */ 1347 struct IAudioManager *audioManagerIns = IAudioManagerGet(g_isDirect); 1348 if (audioManagerIns == NULL) { 1349 AUDIO_FUNC_LOGE("Get Audio Manager Fail"); 1350 return HDF_FAILURE; 1351 } 1352 1353 /* Obtain the audio adapter list. */ 1354 struct AudioAdapterDescriptor *descs = (struct AudioAdapterDescriptor *)OsalMemCalloc( 1355 sizeof(struct AudioAdapterDescriptor) * (MAX_AUDIO_ADAPTER_DESC)); 1356 uint32_t adapterNum = MAX_AUDIO_ADAPTER_DESC; 1357 1358 int32_t ret = audioManagerIns->GetAllAdapters(audioManagerIns, descs, &adapterNum); 1359 1360 /* Locate the audio adapter and port based on the specified audio adapter name and port description. */ 1361 SelectAudioCard(descs, adapterNum, &adapterIndex); 1362 strcpy_s(g_adapterName, PATH_LEN, descs[adapterIndex - 1].adapterName); 1363 SwitchAudioPort(&descs[adapterIndex - 1], PORT_OUT, renderPort); // The port type is OUT, which means playback. 1364 1365 /* Load the audio adapter based on the matched audio adapter information. */ 1366 audioManagerIns->LoadAdapter(audioManagerIns, &descs[adapterIndex - 1], &g_adapter); // Load the audio adapter and obtain the related instances. 1367 1368 /* Create a Render class. */ 1369 uint32_t portId = renderPort->portId; 1370 InitDevDesc(&g_devDesc, portId); // Initialize the parameters for setting the device. 1371 InitAttrs(&g_attrs); // Initialize audio attribute parameters. 1372 CheckWavFileHeader(g_file, &g_wavHeadInfo, &g_attrs); // Parse the audio file and set attributes. 1373 g_adapter->CreateRender(g_adapter, &g_devDesc, &g_attrs, &g_render, &g_renderId); 1374 1375 /* Deliver the number of the audio to be played. */ 1376 g_render->Start((void *)g_render); // Send the start command to start the playback. 1377 pthread_create(&g_tids, &tidsAttr, (void *)(&FrameStart), &g_str); // Start the thread to play the music. 1378 1379 /* Send the control instructions. */ 1380 g_render->Pause((void *)g_render); // Pause the playback. 1381 g_render->Resume((void *)g_render); // Resume the playback. 1382 g_render->SetVolume((void *)g_render, 0.5); // Set the volume. 1383 1384 /* Stop playback and destroy the Render class. */ 1385 g_render->Stop((void *)g_render); 1386 g_adapter->DestroyRender(g_adapter, g_renderId); 1387 /* Unload the audio adapter. */ 1388 audioManagerIns->UnloadAdapter(audioManagerIns, g_adapterName); 1389} 1390``` 1391 1392 1393 1394## Summary 1395 1396This document provides all the key adaptations involved in the audio driver development. It elaborates how to adapt the audio driver and use HDI APIs. You can conduct development based on the chip you use. After reading this document, you will be able to master the audio driver development based on the HDF. 1397