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

Unverified Commit c5949c3b authored by Rohit Sekhar's avatar Rohit Sekhar Committed by Michael Bestas
Browse files

FP5: Import vibrator HAL from lineage-21.0

Change-Id: I6c641cdc3d20e3a0023b68178e3014981f6b279b
parent f1ed246c
Loading
Loading
Loading
Loading

vibrator/Android.bp

0 → 100644
+76 −0
Original line number Diff line number Diff line
Common_CFlags = ["-Wall"]
Common_CFlags += ["-Werror"]

soong_config_module_type {
    name: "vibrator_cc_defaults",
    module_type: "cc_defaults",
    config_namespace: "vibrator",
    variables: ["vibratortargets"],
    properties: ["shared_libs"],
}

soong_config_string_variable {
    name: "vibratortargets",
    values: ["vibratoraidlV2platformtarget", "vibratoraidlV2target"],
}

vibrator_cc_defaults {
    name: "vibrator_defaults",
    soong_config_variables: {
        vibratortargets: {
            vibratoraidlV2platformtarget: {
                 shared_libs: [
                       "android.hardware.vibrator-V2-ndk_platform",
                  ],
            },
            vibratoraidlV2target: {
                 shared_libs: [
                       "android.hardware.vibrator-V2-ndk",
                  ],
            },
        },
    },
}


cc_library_shared {
    name: "vendor.qti.hardware.vibrator.impl",
    defaults: [
        "vibrator_defaults",
        "qti_vibrator_hal_defaults",
    ],
    vendor: true,
    srcs: [
        "Vibrator.cpp",
        "VibratorOffload.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "liblog",
        "libqtivibratoreffectoffload",
        "libbinder_ndk",
    ],
    export_include_dirs: ["include"]
}

cc_binary {
    name: "vendor.qti.hardware.vibrator.service",
    defaults: ["vibrator_defaults"],
    vendor: true,
    relative_install_path: "hw",
    init_rc: ["vendor.qti.hardware.vibrator.service.rc"],
    vintf_fragments: [
        "vendor.qti.hardware.vibrator.service.xml",
    ],
    srcs: [
        "service.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "libbase",
        "libbinder_ndk",
        "vendor.qti.hardware.vibrator.impl",
    ],
}

vibrator/Vibrator.cpp

0 → 100644
+963 −0

File added.

Preview size limit exceeded, changes collapsed.

+321 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
 *
 * Changes from Qualcomm Innovation Center are provided under the following license:
 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
 * SPDX-License-Identifier: BSD-3-Clause-Clear
 */

#define LOG_TAG "vendor.qti.vibrator.offload"

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <thread>
#include <linux/input.h>
#include <log/log.h>
#include <fcntl.h>
#include <cutils/log.h>
#include <cutils/uevent.h>
#include <cutils/properties.h>
#include <sys/poll.h>
#include <sys/ioctl.h>

#include "include/Vibrator.h"
#include "VibratorPatterns.h"

namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {

#define UEVENT_MSG_LEN              1024
#define SLATE_EVENT "SLATE_EVENT="
#define SLATE_EVENT_STRING_LEN      12 //length of SLATE_EVENT
/*
 * TODO Need to work on solution to get this from kernel header
 * without effecting other kernel versions where this change
 * goes in.
 */
#define SLATE_AFTER_POWER_UP        4

PatternOffload::PatternOffload()
{
    char prop_str[PROPERTY_VALUE_MAX];
    mEnabled = 0;

    if (property_get("ro.vendor.qc_aon_presence", prop_str, NULL))
        mEnabled = atoi(prop_str);

    if (mEnabled != 1)
        return;

    std::thread t(&PatternOffload::SSREventListener, this);
    t.detach();
}

void PatternOffload::SSREventListener(void)
{
    int device_fd, n, ssr_event = 0;
    char msg[UEVENT_MSG_LEN + 2];
    char *msg_ptr = msg;

    /* Offload during the bootup */
    SendPatterns();

    device_fd = uevent_open_socket(64*1024, true);
    if(device_fd < 0)
    {
        ALOGE("open socket failed: %d", device_fd);
        return;
    }

    while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
         if (n <= 0 || n > UEVENT_MSG_LEN) {
            ALOGE("Message length %d is not correct\n", n);
            continue;
         }
         msg[n] = '\0';
         msg[n+1] = '\0';
         if (strstr(msg, "slate_com_dev")) {
             while(*msg_ptr) {
                 if(!strncmp(msg_ptr, SLATE_EVENT, SLATE_EVENT_STRING_LEN)) {
                     msg_ptr += SLATE_EVENT_STRING_LEN;
                     ssr_event = (atoi(msg_ptr));
                     switch(ssr_event) {
                         case SLATE_AFTER_POWER_UP:
                             ALOGD("SLATE is powered up");
                             SendPatterns();
                             break;
                     }
                 }
                 while(*msg_ptr++);
             }
         }
     }
}

/** Offload patterns
 *  The sequence of steps in offloading patterns.
 *  1. Open the Glink channel to offload the patterns
 *  2. Send the configuration/meta data to co-proc
 *  3. Wait for the response from the co-proc
 *  4. Send the pattern data to co-proc
 *  5. Wait for the response
 *  6. Exit
 */
void PatternOffload::SendPatterns()
{
    uint8_t *data;
    uint32_t len;
    int32_t rc;

    rc = initChannel();
    if (rc < 0)
        return;

    rc = get_pattern_config(&data, &len);
    if (rc < 0 || !data)
        return;

    /* Send config data */
    rc = sendData(data, len);
    if (rc < 0)
        return;

    rc = get_pattern_data(&data, &len);
    if (rc < 0)
        return;

    /* Send pattern data */
    rc = sendData(data, len);
    if (rc < 0)
        ALOGE("pattern offloaded failed\n");
    else
        ALOGI("Patterns offloaded successfully\n");

    free_pattern_mem(data);
}

int PatternOffload::sendData(uint8_t *data, int len)
{
    int rc, status = 0;

    if (!data || !len)
        return -EINVAL;

    rc = GlinkCh.GlinkWrite(data, len);
    if (rc < 0)
        return rc;

    rc = GlinkCh.GlinkPoll();
    if (rc < 0)
        return rc;

    rc = GlinkCh.GlinkRead((uint8_t *)&status, 4);
    if (rc < 0)
        return rc;

    if (status != OFFLOAD_SUCCESS)
        return -EIO;

    return 0;
}


int PatternOffload::initChannel()
{
    std::string chname = "/dev/glinkpkt_slate_haptics_offload";
    int rc;

    rc = GlinkCh.GlinkOpen(chname);
    if (rc < 0)
    {
        ALOGE("Failed to open Glink channel name %s\n", chname.c_str());
        return rc;
    }

    return 0;
}

#define GLINK_MAX_CONN_RETRIES    60
int OffloadGlinkConnection::GlinkOpen(std::string& dev)
{
    int tries = GLINK_MAX_CONN_RETRIES;
    dev_name = dev;

    do {
        fd = ::open(dev_name.c_str(), O_RDWR);
        tries--;
        if (fd < 0)
        {
            ALOGE("%s: %s: open error(%s)", __func__, dev.c_str(), strerror(errno));
            sleep(1);
        }
    } while(-ETIMEDOUT == errno && tries > 0 );

    return fd;
}

int OffloadGlinkConnection::GlinkClose()
{
    if (fd >= 0)
    {
        ::close(fd);
        fd = -1;
    }
    return 0;
}

int OffloadGlinkConnection::GlinkPoll()
{
    ssize_t rc = 0;
    struct pollfd poll_fd;

    // wait for Rx data available in fd, for 2 seconds timeout
    poll_fd.fd = fd;
    poll_fd.events = POLLIN;

    rc = ::poll(&poll_fd, 1, 2000);

    if(rc > 0)
    {
        if (poll_fd.revents & POLLIN)
            return 0;
    } else if (rc == 0) {
           ALOGE("Glink poll timeout");
    } else {
           ALOGE("Glink poll error: %s\n", strerror(errno));
    }

    return -1;
}

int OffloadGlinkConnection::GlinkRead(uint8_t *data, size_t size)
{
    int rc = 0;
    size_t bytes_read = 0;

    if (fd < 0)
        return -1;

    if (0 != GlinkPoll())
        return -1;

    while (bytes_read < size)
    {
        rc = ::read(fd, data+bytes_read, size-bytes_read);
        if (rc < 0) {
            if (errno != EAGAIN) {
                ALOGE("%s: Read error: %s, rc %d", __func__,
                                strerror(errno), rc);
                goto read_error;
            }
        } else if (rc == 0) {
            ALOGE("%s: Zero length packet received or hardware connection went off",
                    __func__);
        }
        bytes_read += rc;
    }
    return 0;

read_error:
    return -1;
}

int OffloadGlinkConnection::GlinkWrite(uint8_t *buf, size_t buflen)
{
    size_t bytes_written_out = 0;
    int rc = 0;

    if (fd < 0)
        return -1;

    if (!buflen) {
       ALOGE("%s: Invalid buffer len", __func__);
       return 0;
    }

    while (bytes_written_out < buflen) {
        rc = ::write (fd, buf+bytes_written_out, buflen-bytes_written_out);
        if (rc < 0) {
            ALOGE("%s: Write returned failure %d", __func__, rc);
            return errno;
        }
        bytes_written_out += rc;
    }
    rc = 0;

    return rc;
}

}  // namespace vibrator
}  // namespace hardware
}  // namespace android
}  // namespace aidl
+35 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2018, 2020 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.                          -->
<devices>
    <device name="qti-haptics"/>
    <device name="qcom-hv-haptics"/>
    <device name="aw8624_haptic"/>
    <device name="aw8695_haptic"/>
    <device name="aw8697_haptic"/>
    <device name="awinic_haptic"/>
</devices>
+149 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018,2020-2021, 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.
 *
 * Changes from Qualcomm Innovation Center are provided under the following license:
 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
 * SPDX-License-Identifier: BSD-3-Clause-Clear
 */

#pragma once

#include <aidl/android/hardware/vibrator/BnVibrator.h>
#include <thread>

namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {

class InputFFDevice {
public:
    InputFFDevice();
    int playEffect(int effectId, EffectStrength es, long *playLengthMs);
    int playPrimitive(int primitiveId, float amplitude, long *playLengthMs);
    int on(int32_t timeoutMs);
    int off();
    int setAmplitude(uint8_t amplitude);
    bool mSupportGain;
    bool mSupportEffects;
    bool mSupportExternalControl;
    bool mInExternalControl;

private:
    int play(int effectId, uint32_t timeoutMs, long *playLengthMs);
    int mVibraFd;
    int16_t mCurrAppId;
    int16_t mCurrMagnitude;
};

class LedVibratorDevice {
public:
    LedVibratorDevice();
    int on(int32_t timeoutMs);
    int off();
    bool mDetected;
private:
    int write_value(const char *file, const char *value);
};

class OffloadGlinkConnection {
public:
    int GlinkOpen(std::string& dev);
    int GlinkClose();
    int GlinkPoll();
    int GlinkRead(uint8_t *data, size_t size);
    int GlinkWrite(uint8_t *buf, size_t buflen);
private:
    std::string dev_name;
    int fd;
};

class PatternOffload {
public:
    PatternOffload();
    void SSREventListener(void);
    void SendPatterns();
    int mEnabled;
private:
    OffloadGlinkConnection GlinkCh;
    int initChannel();
    int sendData(uint8_t *data, int len);
};

class Vibrator : public BnVibrator {
public:
    class InputFFDevice ff;
    class LedVibratorDevice ledVib;
    Vibrator();
    ~Vibrator();
    class PatternOffload Offload;

    ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
    ndk::ScopedAStatus off() override;
    ndk::ScopedAStatus on(int32_t timeoutMs,
            const std::shared_ptr<IVibratorCallback>& callback) override;
    ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
            const std::shared_ptr<IVibratorCallback>& callback,
            int32_t* _aidl_return) override;
    ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
    ndk::ScopedAStatus setAmplitude(float amplitude) override;
    ndk::ScopedAStatus setExternalControl(bool enabled) override;
    ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
    ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
    ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
    ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
                                            int32_t* durationMs) override;
    ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
                               const std::shared_ptr<IVibratorCallback>& callback) override;
    ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
    ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
    ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
    ndk::ScopedAStatus getResonantFrequency(float *resonantFreqHz) override;
    ndk::ScopedAStatus getQFactor(float *qFactor) override;
    ndk::ScopedAStatus getFrequencyResolution(float *freqResolutionHz) override;
    ndk::ScopedAStatus getFrequencyMinimum(float *freqMinimumHz) override;
    ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) override;
    ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t *durationMs) override;
    ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t *maxSize) override;
    ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
    ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
                               const std::shared_ptr<IVibratorCallback> &callback) override;
private:
    static void composePlayThread(Vibrator *vibrator,
                        const std::vector<CompositeEffect>& composite,
                        const std::shared_ptr<IVibratorCallback>& callback);
    std::thread composeThread;
    int epollfd;
    int pipefd[2];
    std::atomic<bool> inComposition;
};

}  // namespace vibrator
}  // namespace hardware
}  // namespace android
}  // namespace aidl
Loading