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

Commit d2100a6f authored by Balázs Triszka's avatar Balázs Triszka Committed by Bruno Martins
Browse files

hal: Add open source HAL for Elliptic Ultrasound



Author: Balázs Triszka <balika011@gmail.com>
Date:   Mon Feb 26 22:11:10 2018 +0100

    msm8996: ultrasound: Initial open source hal for Elliptic Ultrasound

    * Needed for proximity sensor on Xiaomi Mi MIX

    Change-Id: Iaef2266bc1b853d7a9d1e2a906014c6c91019d5f
    Signed-off-by: default avatarBalázs Triszka <balika011@gmail.com>

Author: Michael Bestas <mkbestas@lineageos.org>
Date:   Sat Feb 10 00:28:00 2018 +0200

    msm8996: ultrasound: Remove unused code

     * Params ultrasound_set_manual_calibration and ultrasound_set_sensitivity
       do not exist.

    Change-Id: I0004949db19b6ab7d49f20e422984e06a970cfe9

Author: Demon Singur <demonsingur@gmail.com>
Date:   Sat Apr 21 09:08:03 2018 +0000

    msm8996: hal: Update ultrasound route hacks

    Change-Id: If002503dfba0f005f73a4455d68bbcce9d2f617e

Change-Id: I798f5a8e4f25c4d192a95befd162b86495ccc178
parent d8cc81aa
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -426,6 +426,11 @@ ifneq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_AMPLIFIER)),false)
    LOCAL_SRC_FILES += audio_extn/audio_amplifier.c
endif

ifeq ($(strip $(AUDIO_FEATURE_ELLIPTIC_ULTRASOUND_SUPPORT)),true)
    LOCAL_CFLAGS += -DELLIPTIC_ULTRASOUND_ENABLED
    LOCAL_SRC_FILES += audio_extn/ultrasound.c
endif

LOCAL_CFLAGS += -Wall -Werror
LOCAL_CLANG_CFLAGS += -Wno-unused-variable -Wno-unused-function -Wno-missing-field-initializers

+254 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017-2018 The LineageOS Project
 * Copyright (c) 2017 Balázs Triszka <balika011@protonmail.ch>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "ultrasound"

#include <errno.h>
#include <stdlib.h>
#include <cutils/log.h>
#include "audio_hw.h"
#include "platform_api.h"
#include <platform.h>
#include "ultrasound.h"

#define ULTRASOUND_CALIBRATION_FILE "/persist/audio/us_cal"
#define ULTRASOUND_CALIBRATION_MIXER "Ultrasound Calibration Data"

enum {
    ULTRASOUND_STATUS_DEFAULT,
    ULTRASOUND_STATUS_STARTED,
    ULTRASOUND_STATUS_STOPPED,
};

struct pcm_config pcm_config_us = {
    .channels = 1,
    .rate = 96000,
    .period_size = 1024,
    .period_count = 2,
    .format = PCM_FORMAT_S16_LE,
};

struct ultrasound_device {
    struct pcm *rx_pcm, *tx_pcm;
    int state;
    struct audio_device *adev;
};

static struct ultrasound_device *us = NULL;

void us_cal_load(void)
{
    FILE *f;
    char buff[5] = {0}, us_cal[64];
    struct mixer_ctl * ctl;
    int rc;

    f = fopen(ULTRASOUND_CALIBRATION_FILE, "r");
    if (!f) {
        ALOGE("%s: Cannot open calibration file: %s",
                __func__, ULTRASOUND_CALIBRATION_FILE);
        return;
    }

    for (size_t i = 0; i < sizeof(us_cal); i++) {
        fread(buff, 1, sizeof(buff), f);
        us_cal[i] = strtol(buff, 0, 16);
    }
    fclose(f);

    ctl = mixer_get_ctl_by_name(us->adev->mixer, ULTRASOUND_CALIBRATION_MIXER);
    if (!ctl) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s",
                __func__, ULTRASOUND_CALIBRATION_MIXER);
        return;
    }

    rc = mixer_ctl_set_array(ctl, us_cal, sizeof(us_cal));
    if (rc < 0)
        ALOGE("%s: Could not set ctl, error:%d ", __func__, rc);
}

int us_init(struct audio_device *adev)
{
    ALOGD("%s: enter", __func__);

    if (us) {
        ALOGI("%s: ultrasound has been initialized!", __func__);
        return 0;
    }

    us = calloc(1, sizeof(struct ultrasound_device));
    if (!us) {
        ALOGE("%s: Out of memory!", __func__);
        return -ENOMEM;
    }

    us->adev = adev;

    us_cal_load();

    ALOGD("%s: exit, status(0)", __func__);

    return 0;
}

void us_deinit(void)
{
    ALOGD("%s: enter", __func__);

    if (us) {
        free(us);
        us = NULL;
    }

    ALOGD("%s: exit", __func__);
}

int stop_us(void)
{
    struct audio_usecase *rx_usecase, *tx_usecase;
    int rc = 0;

    ALOGD("%s: enter usecase: ultrasound", __func__);

    us->state = ULTRASOUND_STATUS_STOPPED;
    if (us->rx_pcm) {
        pcm_close(us->rx_pcm);
        us->rx_pcm = NULL;
    }

    if (us->tx_pcm) {
        pcm_close(us->tx_pcm);
        us->tx_pcm = NULL;
    }

    rx_usecase = get_usecase_from_list(us->adev, USECASE_AUDIO_ULTRASOUND_RX);
    if (!rx_usecase) {
        ALOGE("%s: Could not find the usecase (%d) in the list",
                __func__, USECASE_AUDIO_ULTRASOUND_RX);
        rc = -EINVAL;
    } else {
        disable_audio_route(us->adev, rx_usecase);
        disable_snd_device(us->adev, rx_usecase->out_snd_device);
        list_remove(&rx_usecase->list);
        free(rx_usecase);
    }

    tx_usecase = get_usecase_from_list(us->adev, USECASE_AUDIO_ULTRASOUND_TX);
    if (!rx_usecase) {
        ALOGE("%s: Could not find the usecase (%d) in the list",
                __func__, USECASE_AUDIO_ULTRASOUND_TX);
        rc = -EINVAL;
    } else {
        disable_audio_route(us->adev, tx_usecase);
        disable_snd_device(us->adev, tx_usecase->in_snd_device);
        list_remove(&tx_usecase->list);
        free(tx_usecase);
    }

    ALOGD("%s: exit: status(%d)", __func__, rc);

    return rc;
}

int us_start(void)
{
    int rx_device_id, tx_device_id;
    struct audio_usecase *rx_usecase, *tx_usecase;

    ALOGD("%s: enter", __func__);

    if (!us || us->state == ULTRASOUND_STATUS_STARTED)
        return -EPERM;

    ALOGD("%s: enter usecase: ultrasound", __func__);
    rx_device_id = platform_get_pcm_device_id(USECASE_AUDIO_ULTRASOUND_RX, PCM_PLAYBACK);
    tx_device_id = platform_get_pcm_device_id(USECASE_AUDIO_ULTRASOUND_TX, PCM_CAPTURE);
    if (rx_device_id < 0 || tx_device_id < 0) {
        ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(ultrasound)",
                __func__, rx_device_id, tx_device_id);
        stop_us();
        ALOGE("%s: exit: status(%d)", __func__, -EIO);
        return -EIO;
    }

    rx_usecase = calloc(1, sizeof(struct audio_usecase));
    if (!rx_usecase) {
        ALOGE("%s: Out of memory!", __func__);
        return -ENOMEM;
    }

    rx_usecase->type = PCM_PLAYBACK;
    rx_usecase->out_snd_device = SND_DEVICE_OUT_ULTRASOUND_HANDSET;
    rx_usecase->id = USECASE_AUDIO_ULTRASOUND_RX;
    list_add_tail(&us->adev->usecase_list, &rx_usecase->list);

    enable_snd_device(us->adev, SND_DEVICE_OUT_ULTRASOUND_HANDSET);
    enable_audio_route(us->adev, rx_usecase);
    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
            __func__, us->adev->snd_card, rx_device_id);
    us->rx_pcm = pcm_open(us->adev->snd_card, rx_device_id, PCM_OUT, &pcm_config_us);
    if (us->rx_pcm && !pcm_is_ready(us->rx_pcm)) {
        ALOGE("%s: %s", __func__, pcm_get_error(us->rx_pcm));
        stop_us();
        ALOGE("%s: exit: status(%d)", __func__, -EIO);
        return -EIO;
    }

    tx_usecase = calloc(1, sizeof(struct audio_usecase));
    if (!tx_usecase) {
        ALOGE("%s: Out of memory!", __func__);
        return -ENOMEM;
    }

    tx_usecase->type = PCM_CAPTURE;
    tx_usecase->in_snd_device = SND_DEVICE_IN_ULTRASOUND_MIC;
    tx_usecase->id = USECASE_AUDIO_ULTRASOUND_TX;
    list_add_tail(&us->adev->usecase_list, &tx_usecase->list);

    enable_snd_device(us->adev, SND_DEVICE_IN_ULTRASOUND_MIC);
    enable_audio_route(us->adev, tx_usecase);
    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
            __func__, us->adev->snd_card, tx_device_id);
    us->tx_pcm = pcm_open(us->adev->snd_card, tx_device_id, PCM_IN, &pcm_config_us);
    if (us->tx_pcm && !pcm_is_ready(us->tx_pcm)) {
        ALOGD("%s: %s", __func__, pcm_get_error(us->tx_pcm));
        stop_us();
        ALOGE("%s: exit: status(%d)", __func__, -EIO);
        return -EIO;
    }

    pcm_start(us->rx_pcm);
    pcm_start(us->tx_pcm);
    us->state = ULTRASOUND_STATUS_STARTED;

    ALOGD("%s: exit, status(0)", __func__);

    return 0;
}

int us_stop(void)
{
    ALOGD("%s: enter", __func__);

    if (!us || us->state != ULTRASOUND_STATUS_STARTED)
        return -EPERM;

    stop_us();

    return 0;
}
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017-2018 The LineageOS Project
 * Copyright (c) 2017 Balázs Triszka <balika011@protonmail.ch>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ULTRASOUND_H
#define ULTRASOUND_H

#ifndef ELLIPTIC_ULTRASOUND_ENABLED
#define us_init(adev) (0)
#define us_deinit() (0)
#define us_start() (0)
#define us_stop() (0)
#else
int us_init(struct audio_device *adev);
void us_deinit(void);
int us_start(void);
int us_stop(void);
#endif

#endif
+39 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@
#include "voice_extn.h"
#include "ip_hdlr_intf.h"
#include "audio_amplifier.h"
#include "ultrasound.h"

#include "sound/compress_params.h"
#include "sound/asound.h"
@@ -354,7 +355,11 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {

    [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",

    [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback"
    [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",

    /* For Elliptic Ultrasound proximity sensor */
    [USECASE_AUDIO_ULTRASOUND_RX] = "ultrasound-rx",
    [USECASE_AUDIO_ULTRASOUND_TX] = "ultrasound-tx",
};

static const audio_usecase_t offload_usecases[] = {
@@ -984,6 +989,9 @@ int enable_audio_route(struct audio_device *adev,
    audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
    audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
    audio_extn_utils_send_app_type_cfg(adev, usecase);
#ifdef ELLIPTIC_ULTRASOUND_ENABLED
    if (usecase->id != USECASE_AUDIO_ULTRASOUND_TX)
#endif
    audio_extn_utils_send_audio_calibration(adev, usecase);
    if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
        out = usecase->stream.out;
@@ -1087,6 +1095,10 @@ int enable_snd_device(struct audio_device *adev,
                                        ST_EVENT_SND_DEVICE_BUSY);
        audio_extn_listen_update_device_status(snd_device,
                                        LISTEN_EVENT_SND_DEVICE_BUSY);
#ifdef ELLIPTIC_ULTRASOUND_ENABLED
        if (snd_device != SND_DEVICE_OUT_ULTRASOUND_HANDSET &&
                snd_device != SND_DEVICE_IN_ULTRASOUND_MIC)
#endif
        if (platform_get_snd_device_acdb_id(snd_device) < 0) {
            adev->snd_dev_ref_cnt[snd_device]--;
            audio_extn_sound_trigger_update_device_status(snd_device,
@@ -1380,6 +1392,12 @@ static void check_usecases_codec_backend(struct audio_device *adev,
              platform_get_snd_device_name(snd_device),
              platform_get_snd_device_name(usecase->out_snd_device),
              platform_check_backends_match(snd_device, usecase->out_snd_device));

#ifdef ELLIPTIC_ULTRASOUND_ENABLED
        if (usecase->id == USECASE_AUDIO_ULTRASOUND_RX)
            continue;
#endif

        if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
            uc_derive_snd_device = derive_playback_snd_device(adev->platform,
                                               usecase, uc_info, snd_device);
@@ -1499,6 +1517,12 @@ static void check_usecases_capture_codec_backend(struct audio_device *adev,
        /*
         * TODO: Enhance below condition to handle BT sco/USB multi recording
         */

#ifdef ELLIPTIC_ULTRASOUND_ENABLED
        if (usecase->id == USECASE_AUDIO_ULTRASOUND_TX)
            continue;
#endif

        if (usecase->type != PCM_PLAYBACK &&
                usecase != uc_info &&
                (usecase->in_snd_device != snd_device || force_routing) &&
@@ -6610,6 +6634,15 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
        }
    }

    ret = str_parms_get_int(parms, "ultrasound_enable", &val);
    if (ret >= 0) {
        if (val == 1) {
            us_start();
        } else {
            us_stop();
        }
    }

    amplifier_set_parameters(parms);
    audio_extn_set_parameters(adev, parms);
done:
@@ -7295,6 +7328,9 @@ static int adev_close(hw_device_t *device)
        free(device);
        adev = NULL;
    }

    us_deinit();

    pthread_mutex_unlock(&adev_init_lock);

    return 0;
@@ -7633,6 +7669,8 @@ static int adev_open(const hw_module_t *module, const char *name,
    if (amplifier_open(adev) != 0)
        ALOGE("Amplifier initialization failed");

    us_init(adev);

    *device = &adev->device.common;
    adev->dsp_bit_width_enforce_mode =
        adev_init_dsp_bit_width_enforce_mode(adev->mixer);
+3 −0
Original line number Diff line number Diff line
@@ -205,6 +205,9 @@ enum {

    USECASE_AUDIO_A2DP_ABR_FEEDBACK,

    USECASE_AUDIO_ULTRASOUND_RX,
    USECASE_AUDIO_ULTRASOUND_TX,

    AUDIO_USECASE_MAX
};

Loading