前文我们讲到了AudioCardInit函数,这个函数是初始化函数,首先我们看一下源码
static int32_t AudioCardInit(struct HdfDeviceObject *device, struct AudioHost *audioHost)
{
int32_t ret;
struct AudioCard *audioCard = NULL;
if (device == NULL || audioHost == NULL) {
ADM_LOG_ERR("device or audioHost is NULL.");
return HDF_FAILURE;
}
audioCard = (struct AudioCard *)OsalMemCalloc(sizeof(*audioCard));
if (audioCard == NULL) {
ADM_LOG_ERR("Malloc audioCard fail!");
return HDF_FAILURE;
}
audioHost->priv = audioCard;
/* Get node information through HCS file */
ret = AudioFillConfigData(device, &(audioCard->configData));
if (ret != HDF_SUCCESS) {
ADM_LOG_ERR("AudioFillConfigData fail ret=%d", ret);
return HDF_ERR_IO;
}
audioCard->device = device;
audioCard->standbyMode = AUDIO_SAPM_TURN_STANDBY_LATER;
/* Bind specific codec、platform and dai device */
ret = AudioBindDaiLink(audioCard, &(audioCard->configData));
if (ret != HDF_SUCCESS) {
ADM_LOG_ERR("AudioBindDaiLink fail ret=%d", ret);
return HDF_FAILURE;
}
if (audioCard->rtd == NULL || (!audioCard->rtd->complete)) {
ADM_LOG_ERR("AudioBindDaiLink fail!");
return HDF_ERR_IO;
}
/* Initialize controls list */
DListHeadInit(&audioCard->controls);
DListHeadInit(&audioCard->components);
DListHeadInit(&audioCard->paths);
DListHeadInit(&audioCard->sapmDirty);
/* Initialize hardware device */
ret = AudioInitDaiLink(audioCard);
if (ret != HDF_SUCCESS) {
ADM_LOG_ERR("AudioInitDaiLink fail ret=%d", ret);
return HDF_ERR_IO;
}
/* sound card added to list */
DListInsertHead(&audioCard->list, &cardManager);
return HDF_SUCCESS;
}
首先我们看一下这个函数AudioFillConfigData,这个函数就是解析声卡配置文件audio_config.hcs,解析此声卡包含的驱动服务名称,包括codec、dai、dma服务代码如下。然后调用AudioBindDaiLink根据找到驱动服务名称找到相应的驱动服务和声卡进行绑定,接着是一些链表的初始化,这些链表包括控制链表、电源管理的组件链表和声卡的通路链表等,最后调用AudioInitDaiLink将声卡对应的codec、dai、dma驱动进行初始化,最后再将此声卡插入到声卡链表中。
serviceRet = drsOps->GetString(node, "serviceName", &(configData->cardServiceName), 0);
codecRet = drsOps->GetString(node, "codecName", &(configData->codecName), 0);
platformRet = drsOps->GetString(node, "platformName", &(configData->platformName), 0);
cpuRet = drsOps->GetString(node, "cpuDaiName", &(configData->cpuDaiName), 0);
codeDaiRet = drsOps->GetString(node, "codecDaiName", &(configData->codecDaiName), 0);
dspRet = drsOps->GetString(node, "dspName", &(configData->dspName), 0);
dspDaiRet = drsOps->GetString(node, "dspDaiName", &(configData->dspDaiName), 0);
然后我们看一下AudioBindDaiLink函数,这个函数的作用就是将codec、dai、dma驱动和声卡绑定,上面那个函数找到了配置文件中的声卡对应的驱动名称这里做个绑定,源码如下:
int32_t AudioBindDaiLink(struct AudioCard *audioCard, const struct AudioConfigData *configData)
{
if (audioCard == NULL) {
ADM_LOG_ERR("Input params check error: audioCard is NULL.");
return HDF_ERR_INVALID_OBJECT;
}
if (configData == NULL) {
ADM_LOG_ERR("Input params check error: configData is NULL.");
return HDF_ERR_INVALID_OBJECT;
}
audioCard->rtd = (struct AudioRuntimeDeivces *)OsalMemCalloc(sizeof(struct AudioRuntimeDeivces));
if (audioCard->rtd == NULL) {
ADM_LOG_ERR("Malloc audioCard->rtd fail!");
return HDF_ERR_MALLOC_FAIL;
}
audioCard->rtd->complete = AUDIO_DAI_LINK_UNCOMPLETE;
if (AudioSeekPlatformDevice(audioCard->rtd, configData) == HDF_SUCCESS) {
ADM_LOG_DEBUG("PLATFORM [%s] is registered!", configData->platformName);
}
if (AudioSeekCpuDaiDevice(audioCard->rtd, configData) == HDF_SUCCESS) {
ADM_LOG_DEBUG("CPU DAI [%s] is registered!", configData->cpuDaiName);
}
if (AudioSeekCodecDevice(audioCard->rtd, configData) == HDF_SUCCESS) {
ADM_LOG_DEBUG("CODEC [%s] is registered!", configData->codecName);
}
if (AudioSeekDspDevice(audioCard->rtd, configData) == HDF_SUCCESS) {
ADM_LOG_DEBUG("CODEC [%s] is registered!", configData->dspName);
}
audioCard->rtd->complete = AUDIO_DAI_LINK_COMPLETE;
ADM_LOG_DEBUG("All devices register complete!");
return HDF_SUCCESS;
}
这块代码可以看到调用了很多seek函数,这些seek函数的功能是在相应的驱动链表中找到此声卡对应的驱动服务,这些驱动服务链表是在系统驱动的时候各个驱动注册进去的。我们就以codec为例看看他是怎么注册的。
下面是一个codec的init函数,在系统启动的时候会调用。
static int32_t Rk809DriverInit(struct HdfDeviceObject *device)
{
int32_t ret;
struct regmap_config codecRegmapCfg = getCodecRegmap();
struct platform_device *codeDev = GetCodecPlatformDevice();
struct rk808 *rk808 = NULL;
if (!codeDev) {
AUDIO_DEVICE_LOG_ERR("codeDev not ready");
return HDF_FAILURE;
}
g_chip = devm_kzalloc(&codeDev->dev, sizeof(struct Rk809ChipData), GFP_KERNEL);
if (!g_chip) {
AUDIO_DEVICE_LOG_ERR("devm_kzalloc for g_chip failed!");
return HDF_ERR_MALLOC_FAIL;
}
g_chip->codec = g_rk809Data;
g_chip->dai = g_rk809DaiData;
platform_set_drvdata(codeDev, g_chip);
g_chip->pdev = codeDev;
rk808 = dev_get_drvdata(g_chip->pdev->dev.parent);
if (!rk808) {
return HDF_FAILURE;
}
g_chip->regmap = devm_regmap_init_i2c(rk808->i2c, &codecRegmapCfg);
if (IS_ERR(g_chip->regmap)) {
AUDIO_DEVICE_LOG_ERR("failed to allocate regmap: %ld\n", PTR_ERR(g_chip->regmap));
return HDF_FAILURE;
}
if (CodecDaiGetPortConfigInfo(device, &g_rk809DaiData) != HDF_SUCCESS) {
return HDF_FAILURE;
}
if (CodecGetConfigInfo(device, &g_rk809Data) != HDF_SUCCESS) {
return HDF_FAILURE;
}
if (CodecSetConfigInfoOfControls(&g_rk809Data, &g_rk809DaiData) != HDF_SUCCESS) {
return HDF_FAILURE;
}
ret = CodecGetServiceName(device, &(g_rk809Data.drvCodecName));
if (ret != HDF_SUCCESS) {
return ret;
}
ret = CodecGetDaiName(device, &(g_rk809DaiData.drvDaiName));
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
OsalMutexInit(&g_rk809Data.mutex);
OsalMutexInit(&g_rk809DaiData.mutex);
ret = AudioRegisterCodec(device, &g_rk809Data, &g_rk809DaiData);
if (ret != HDF_SUCCESS) {
return ret;
}
return HDF_SUCCESS;
}
这个函数的功能就是做codec数据的初始化,通过解析hcs配置文件解析来我们codec私有HCS文件中的配置信息。最后会调用AudioRegisterCodec函数将此codec注册到codec设备链表中。
我们一起来看一下AudioRegisterCodec源码:
int32_t AudioRegisterCodec(struct HdfDeviceObject *device, struct CodecData *codecData, struct DaiData *daiData)
{
struct CodecDevice *codec = NULL;
int32_t ret;
if (device == NULL) {
ADM_LOG_ERR("Input params check error: device is NULL.");
return HDF_ERR_INVALID_OBJECT;
}
if (codecData == NULL) {
ADM_LOG_ERR("Input params check error: codecData is NULL.");
return HDF_ERR_INVALID_OBJECT;
}
if (daiData == NULL) {
ADM_LOG_ERR("Input params check error: daiData is NULL.");
return HDF_ERR_INVALID_OBJECT;
}
codec = (struct CodecDevice *)OsalMemCalloc(sizeof(*codec));
if (codec == NULL) {
ADM_LOG_ERR("Malloc codec device fail!");
return HDF_ERR_MALLOC_FAIL;
}
codec->devCodecName = codecData->drvCodecName;
codec->devData = codecData;
codec->device = device;
ret = AudioSocRegisterDai(device, daiData);
if (ret != HDF_SUCCESS) {
OsalIoUnmap((void *)((uintptr_t)(codec->devData->virtualAddress)));
OsalMemFree(codec);
ADM_LOG_ERR("Register dai device fail ret=%d", ret);
return HDF_ERR_IO;
}
DListInsertHead(&codec->list, &codecController);
ADM_LOG_INFO("Register [%s] success.", codec->devCodecName);
return HDF_SUCCESS;
}
AudioRegisterCodec这个函数最终会调用DListInsertHead(&codec->list, &codecController);将codec插入到codecController链表中。声卡初始化的时候就会遍历此链表找到相应的codec。