Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1153fd55 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "hal: add support for automotive audio hal extension"

parents 967f3ea3 ae7b0349
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -509,6 +509,11 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_GCOV)),true)
    LOCAL_STATIC_LIBRARIES += libprofile_rt
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUTO_HAL)),true)
    LOCAL_CFLAGS += -DAUDIO_EXTN_AUTO_HAL_ENABLED
    LOCAL_SRC_FILES += audio_extn/auto_hal.c
endif

ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HW_PLUGIN)),true)
    LOCAL_CFLAGS += -DEXT_HW_PLUGIN_ENABLED
    LOCAL_SRC_FILES += audio_extn/ext_hw_plugin.c
+12 −0
Original line number Diff line number Diff line
@@ -1146,6 +1146,18 @@ void audio_extn_ffv_append_ec_ref_dev_name(char *device_name);

int audio_extn_utils_get_license_params(const struct audio_device *adev,  struct audio_license_params *lic_params);

#ifndef AUDIO_EXTN_AUTO_HAL_ENABLED
#define audio_extn_auto_hal_init(adev)                (0)
#define audio_extn_auto_hal_deinit()                  (0)
#define audio_extn_auto_hal_enable_hostless()         (0)
#define audio_extn_auto_hal_disable_hostless()        (0)
#else
int32_t audio_extn_auto_hal_init(struct audio_device *adev);
void audio_extn_auto_hal_deinit(void);
int32_t audio_extn_auto_hal_enable_hostless(void);
void audio_extn_auto_hal_disable_hostless(void);
#endif

#ifndef EXT_HW_PLUGIN_ENABLED
#define audio_extn_ext_hw_plugin_init(adev)                (0)
#define audio_extn_ext_hw_plugin_deinit(plugin)              (0)
+196 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2019 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#define LOG_TAG "auto_hal_extn"
/*#define LOG_NDEBUG 0*/

#include <errno.h>
#include <pthread.h>
#include <cutils/log.h>
#include <math.h>
#include <audio_hw.h>
#include "audio_extn.h"
#include "platform_api.h"
#include "platform.h"
#include "audio_hal_plugin.h"

#ifdef DYNAMIC_LOG_ENABLED
#include <log_xml_parser.h>
#define LOG_MASK HAL_MOD_FILE_AUTO_HAL
#include <log_utils.h>
#endif

#ifdef AUDIO_EXTN_AUTO_HAL_ENABLED

struct hostless_config {
    struct pcm *pcm_tx;
    struct pcm *pcm_rx;
};

typedef struct auto_hal_module {
    struct audio_device *adev;
    struct hostless_config hostless;
} auto_hal_module_t;

/* Auto hal module struct */
static struct auto_hal_module *auto_hal = NULL;

/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are
 * both connected with CODEC and a single master is needed to provide
 * consistent CLK and FSYNC to slaves, hence configuring SoC TERT TDM as
 * single master and bring up a dummy hostless from TERT to SEC to ensure
 * both slave SoC SEC TDM and CODEC are driven upon system boot. */
int32_t audio_extn_auto_hal_enable_hostless(void)
{
    int32_t ret = 0;
    char mixer_path[MIXER_PATH_MAX_LENGTH];

    ALOGD("%s: Enable TERT -> SEC Hostless", __func__);

    if (auto_hal == NULL) {
        ALOGE("%s: Invalid device", __func__);
        return -EINVAL;
    }

    strlcpy(mixer_path, "dummy-hostless", MIXER_PATH_MAX_LENGTH);
    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
    if (audio_route_apply_and_update_path(auto_hal->adev->audio_route,
            mixer_path)) {
        ALOGD("%s: %s not supported, continue", __func__, mixer_path);
        return ret;
    }

    /* TERT TDM TX 7 HOSTLESS to SEC TDM RX 7 HOSTLESS */
    int pcm_dev_rx = 48, pcm_dev_tx = 49;
    struct pcm_config pcm_config_lb = {
        .channels = 1,
        .rate = 48000,
        .period_size = 240,
        .period_count = 2,
        .format = PCM_FORMAT_S16_LE,
        .start_threshold = 0,
        .stop_threshold = INT_MAX,
        .avail_min = 0,
    };

    auto_hal->hostless.pcm_tx = pcm_open(auto_hal->adev->snd_card,
                                   pcm_dev_tx,
                                   PCM_IN, &pcm_config_lb);
    if (auto_hal->hostless.pcm_tx &&
        !pcm_is_ready(auto_hal->hostless.pcm_tx)) {
        ALOGE("%s: %s", __func__,
            pcm_get_error(auto_hal->hostless.pcm_tx));
        ret = -EIO;
        goto error;
    }
    auto_hal->hostless.pcm_rx = pcm_open(auto_hal->adev->snd_card,
                                   pcm_dev_rx,
                                   PCM_OUT, &pcm_config_lb);
    if (auto_hal->hostless.pcm_rx &&
        !pcm_is_ready(auto_hal->hostless.pcm_rx)) {
        ALOGE("%s: %s", __func__,
            pcm_get_error(auto_hal->hostless.pcm_rx));
        ret = -EIO;
        goto error;
    }

    if (pcm_start(auto_hal->hostless.pcm_tx) < 0) {
        ALOGE("%s: pcm start for pcm tx failed", __func__);
        ret = -EIO;
        goto error;
    }
    if (pcm_start(auto_hal->hostless.pcm_rx) < 0) {
        ALOGE("%s: pcm start for pcm rx failed", __func__);
        ret = -EIO;
        goto error;
    }
    return ret;

error:
    if (auto_hal->hostless.pcm_rx)
        pcm_close(auto_hal->hostless.pcm_rx);
    if (auto_hal->hostless.pcm_tx)
        pcm_close(auto_hal->hostless.pcm_tx);
    return ret;
}

void audio_extn_auto_hal_disable_hostless(void)
{
    ALOGD("%s: Disable TERT -> SEC Hostless", __func__);

    if (auto_hal == NULL) {
        ALOGE("%s: Invalid device", __func__);
        return;
    }

    if (auto_hal->hostless.pcm_tx) {
        pcm_close(auto_hal->hostless.pcm_tx);
        auto_hal->hostless.pcm_tx = NULL;
    }
    if (auto_hal->hostless.pcm_rx) {
        pcm_close(auto_hal->hostless.pcm_rx);
        auto_hal->hostless.pcm_rx = NULL;
    }
}

int32_t audio_extn_auto_hal_init(struct audio_device *adev)
{
    int32_t ret = 0;

    if (auto_hal != NULL) {
        ALOGD("%s: Auto hal module already exists",
                __func__);
        return ret;
    }

    auto_hal = calloc(1, sizeof(struct auto_hal_module));

    if (auto_hal == NULL) {
        ALOGE("%s: Memory allocation failed for auto hal module",
                __func__);
        return -ENOMEM;
    }

    auto_hal->adev = adev;

    return ret;
}

void audio_extn_auto_hal_deinit(void)
{
    if (auto_hal == NULL) {
        ALOGE("%s: Auto hal module is NULL, cannot deinitialize",
                __func__);
        return;
    }

    free(auto_hal);

    return;
}
#endif /* AUDIO_EXTN_AUTO_HAL_ENABLED */
+4 −89
Original line number Diff line number Diff line
@@ -48,11 +48,6 @@ typedef int32_t (*audio_hal_plugin_deinit_t)(void);
typedef int32_t (*audio_hal_plugin_send_msg_t)(audio_hal_plugin_msg_type_t,
                                           void *, uint32_t);

struct hostless_module {
    struct pcm *pcm_tx;
    struct pcm *pcm_rx;
};

struct ext_hw_plugin_data {
    struct audio_device           *adev;
    void                          *plugin_handle;
@@ -63,91 +58,11 @@ struct ext_hw_plugin_data {
    snd_device_t                   out_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
    snd_device_t                   in_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
    bool                           mic_mute;
    struct hostless_module         adev_hostless;
};

/* This can be defined in platform specific file or use compile flag */
#define LIB_PLUGIN_DRIVER "libaudiohalplugin.so"

/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are 
 * both connected with CODEC and a single master is needed to provide
 * consistent CLK and FSYNC to slaves, hence configuring SoC TERT TDM as
 * single master and bring up a dummy hostless from TERT to SEC to ensure
 * both slave SoC SEC TDM and CODEC are driven upon system boot. */
static void audio_extn_ext_hw_plugin_enable_adev_hostless(void *plugin)
{
    struct ext_hw_plugin_data *my_plugin =
        (struct ext_hw_plugin_data *)plugin;
    char mixer_path[MIXER_PATH_MAX_LENGTH];

    ALOGI("%s: Enable TERT -> SEC Hostless", __func__);

    strlcpy(mixer_path, "dummy-hostless", MIXER_PATH_MAX_LENGTH);
    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
    if (audio_route_apply_and_update_path(my_plugin->adev->audio_route,
            mixer_path)) {
        ALOGE("%s: %s not supported, continue", __func__, mixer_path);
        return;
    }

    /* TERT TDM TX 7 HOSTLESS to SEC TDM RX 7 HOSTLESS */
    int pcm_dev_rx = 48, pcm_dev_tx = 49;
    struct pcm_config pcm_config_lb = {
        .channels = 1,
        .rate = 48000,
        .period_size = 240,
        .period_count = 2,
        .format = PCM_FORMAT_S16_LE,
        .start_threshold = 0,
        .stop_threshold = INT_MAX,
        .avail_min = 0,
    };

    my_plugin->adev_hostless.pcm_tx = pcm_open(my_plugin->adev->snd_card,
                                   pcm_dev_tx,
                                   PCM_IN, &pcm_config_lb);
    if (my_plugin->adev_hostless.pcm_tx &&
        !pcm_is_ready(my_plugin->adev_hostless.pcm_tx)) {
        ALOGE("%s: %s", __func__,
            pcm_get_error(my_plugin->adev_hostless.pcm_tx));
        return;
    }
    my_plugin->adev_hostless.pcm_rx = pcm_open(my_plugin->adev->snd_card,
                                   pcm_dev_rx,
                                   PCM_OUT, &pcm_config_lb);
    if (my_plugin->adev_hostless.pcm_rx &&
        !pcm_is_ready(my_plugin->adev_hostless.pcm_rx)) {
        ALOGE("%s: %s", __func__,
            pcm_get_error(my_plugin->adev_hostless.pcm_rx));
        return;
    }

    if (pcm_start(my_plugin->adev_hostless.pcm_tx) < 0) {
        ALOGE("%s: pcm start for pcm tx failed", __func__);
        return;
    }
    if (pcm_start(my_plugin->adev_hostless.pcm_rx) < 0) {
        ALOGE("%s: pcm start for pcm rx failed", __func__);
        return;
    }
}

static void audio_extn_ext_hw_plugin_disable_adev_hostless(void *plugin)
{
    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;

    ALOGI("%s: Disable TERT -> SEC Hostless", __func__);

    if (my_plugin->adev_hostless.pcm_tx) {
        pcm_close(my_plugin->adev_hostless.pcm_tx);
        my_plugin->adev_hostless.pcm_tx = NULL;
    }
    if (my_plugin->adev_hostless.pcm_rx) {
        pcm_close(my_plugin->adev_hostless.pcm_rx);
        my_plugin->adev_hostless.pcm_rx = NULL;
    }
}

void* audio_extn_ext_hw_plugin_init(struct audio_device *adev)
{
    int32_t ret = 0;
@@ -162,6 +77,8 @@ void* audio_extn_ext_hw_plugin_init(struct audio_device *adev)

    my_plugin->adev = adev;

    (void)audio_extn_auto_hal_enable_hostless();

    my_plugin->plugin_handle = dlopen(LIB_PLUGIN_DRIVER, RTLD_NOW);
    if (my_plugin->plugin_handle == NULL) {
        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_PLUGIN_DRIVER);
@@ -200,8 +117,6 @@ void* audio_extn_ext_hw_plugin_init(struct audio_device *adev)
        }
    }

    audio_extn_ext_hw_plugin_enable_adev_hostless(my_plugin);

    my_plugin->mic_mute = false;
    return my_plugin;

@@ -222,8 +137,6 @@ int32_t audio_extn_ext_hw_plugin_deinit(void *plugin)
        return -EINVAL;
    }

    audio_extn_ext_hw_plugin_disable_adev_hostless(my_plugin);

    if (my_plugin->audio_hal_plugin_deinit) {
        ret = my_plugin->audio_hal_plugin_deinit();
        if (ret) {
@@ -234,6 +147,8 @@ int32_t audio_extn_ext_hw_plugin_deinit(void *plugin)
    if(my_plugin->plugin_handle != NULL)
        dlclose(my_plugin->plugin_handle);

    audio_extn_auto_hal_disable_hostless();

    free(my_plugin);
    return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -8278,6 +8278,7 @@ static int adev_close(hw_device_t *device)
        }
        if(adev->ext_hw_plugin)
            audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
        audio_extn_auto_hal_deinit();
        free(device);
        adev = NULL;
    }
@@ -8538,6 +8539,7 @@ static int adev_open(const hw_module_t *module, const char *name,
        adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
    }

    audio_extn_auto_hal_init(adev);
    adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);

    if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {