diff options
| author | kleidione Freitas <kleidione@gmail.com> | 2022-03-24 09:16:43 -0300 | 
|---|---|---|
| committer | kleidione <kleidione@gmail.com> | 2022-11-09 17:29:16 -0300 | 
| commit | 44d5c9e2cf9f1ce0670be5bedd1e415cd5c3e739 (patch) | |
| tree | 4516fedba0c65fda9e795d8737d08a7746d41e40 /vibrator | |
| parent | 15eeafbf239f393fcb6ed1a719398e5b7bbd6a19 (diff) | |
veux: Merge common tree to veux
- Ref:
  https://github.com/xiaomi-sm6375-devs/android_device_xiaomi_sm6375-common
Signed-off-by: kleidione <kleidione@gmail.com>
Diffstat (limited to 'vibrator')
| -rw-r--r-- | vibrator/Android.bp | 42 | ||||
| -rw-r--r-- | vibrator/Vibrator.cpp | 587 | ||||
| -rw-r--r-- | vibrator/excluded-input-devices.xml | 32 | ||||
| -rw-r--r-- | vibrator/include/Vibrator.h | 96 | ||||
| -rw-r--r-- | vibrator/service.cpp | 50 | ||||
| -rw-r--r-- | vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.rc | 4 | ||||
| -rw-r--r-- | vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.xml | 33 | 
7 files changed, 844 insertions, 0 deletions
diff --git a/vibrator/Android.bp b/vibrator/Android.bp new file mode 100644 index 0000000..e9d6056 --- /dev/null +++ b/vibrator/Android.bp @@ -0,0 +1,42 @@ +Common_CFlags = ["-Wall"] +Common_CFlags += ["-Werror"] + +cc_library_shared { +    name: "vendor.qti.hardware.vibrator.impl.xiaomi_holi", +    vendor: true, +    cflags: Common_CFlags, +    srcs: [ +        "Vibrator.cpp", +    ], +    shared_libs: [ +        "libcutils", +        "libutils", +        "liblog", +        "libqtivibratoreffect", +        "libbinder_ndk", +        "android.hardware.vibrator-V1-ndk_platform", +    ], +    export_include_dirs: ["include"] +} + +cc_binary { +    name: "vendor.qti.hardware.vibrator.service.xiaomi_holi", +    vendor: true, +    relative_install_path: "hw", +    init_rc: ["vendor.qti.hardware.vibrator.service.xiaomi_holi.rc"], +    vintf_fragments: [ +        "vendor.qti.hardware.vibrator.service.xiaomi_holi.xml", +    ], +    cflags: Common_CFlags, +    srcs: [ +        "service.cpp", +    ], +    shared_libs: [ +        "libcutils", +        "libutils", +        "libbase", +        "libbinder_ndk", +        "android.hardware.vibrator-V1-ndk_platform", +        "vendor.qti.hardware.vibrator.impl.xiaomi_holi", +    ], +} diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp new file mode 100644 index 0000000..629eb18 --- /dev/null +++ b/vibrator/Vibrator.cpp @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2018-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. + */ + +#define LOG_TAG "vendor.qti.vibrator.xiaomi_holi" + +#include <cutils/properties.h> +#include <dirent.h> +#include <inttypes.h> +#include <linux/input.h> +#include <log/log.h> +#include <string.h> +#include <sys/ioctl.h> +#include <thread> + +#include "include/Vibrator.h" +#ifdef USE_EFFECT_STREAM +#include "effect.h" +#endif + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +#define STRONG_MAGNITUDE        0x7fff +#define MEDIUM_MAGNITUDE        0x5fff +#define LIGHT_MAGNITUDE         0x3fff +#define INVALID_VALUE           -1 +#define CUSTOM_DATA_LEN         3 +#define NAME_BUF_SIZE           32 + +#define MSM_CPU_LAHAINA         415 +#define APQ_CPU_LAHAINA         439 +#define MSM_CPU_SHIMA           450 +#define MSM_CPU_SM8325          501 +#define APQ_CPU_SM8325P         502 +#define MSM_CPU_YUPIK           475 + +#define test_bit(bit, array)    ((array)[(bit)/8] & (1<<((bit)%8))) + +static const char LED_DEVICE[] = "/sys/class/leds/vibrator"; + +InputFFDevice::InputFFDevice() +{ +    DIR *dp; +    FILE *fp = NULL; +    struct dirent *dir; +    uint8_t ffBitmask[FF_CNT / 8]; +    char devicename[PATH_MAX]; +    const char *INPUT_DIR = "/dev/input/"; +    char name[NAME_BUF_SIZE]; +    int fd, ret; +    int soc = property_get_int32("ro.vendor.qti.soc_id", -1); + +    mVibraFd = INVALID_VALUE; +    mSupportGain = false; +    mSupportEffects = false; +    mSupportExternalControl = false; +    mCurrAppId = INVALID_VALUE; +    mCurrMagnitude = 0x7fff; +    mInExternalControl = false; + +    dp = opendir(INPUT_DIR); +    if (!dp) { +        ALOGE("open %s failed, errno = %d", INPUT_DIR, errno); +        return; +    } + +    memset(ffBitmask, 0, sizeof(ffBitmask)); +    while ((dir = readdir(dp)) != NULL){ +        if (dir->d_name[0] == '.' && +            (dir->d_name[1] == '\0' || +             (dir->d_name[1] == '.' && dir->d_name[2] == '\0'))) +            continue; + +        snprintf(devicename, PATH_MAX, "%s%s", INPUT_DIR, dir->d_name); +        fd = TEMP_FAILURE_RETRY(open(devicename, O_RDWR)); +        if (fd < 0) { +            ALOGE("open %s failed, errno = %d", devicename, errno); +            continue; +        } + +        ret = TEMP_FAILURE_RETRY(ioctl(fd, EVIOCGNAME(sizeof(name)), name)); +        if (ret == -1) { +            ALOGE("get input device name %s failed, errno = %d\n", devicename, errno); +            close(fd); +            continue; +        } + +        if (strcmp(name, "qcom-hv-haptics") && strcmp(name, "qti-haptics") && +                strcmp(name, "aw8624_haptic")) { +            ALOGD("not a qcom/qti haptics device\n"); +            close(fd); +            continue; +        } + +        ALOGI("%s is detected at %s\n", name, devicename); +        ret = TEMP_FAILURE_RETRY(ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffBitmask)), ffBitmask)); +        if (ret == -1) { +            ALOGE("ioctl failed, errno = %d", errno); +            close(fd); +            continue; +        } + +        if (test_bit(FF_CONSTANT, ffBitmask) || +                test_bit(FF_PERIODIC, ffBitmask)) { +            mVibraFd = fd; +            if (test_bit(FF_CUSTOM, ffBitmask)) +                mSupportEffects = true; +            if (test_bit(FF_GAIN, ffBitmask)) +                mSupportGain = true; + +            if (soc <= 0 && (fp = fopen("/sys/devices/soc0/soc_id", "r")) != NULL) { +                fscanf(fp, "%u", &soc); +                fclose(fp); +            } +            switch (soc) { +            case MSM_CPU_LAHAINA: +            case APQ_CPU_LAHAINA: +            case MSM_CPU_SHIMA: +            case MSM_CPU_SM8325: +            case APQ_CPU_SM8325P: +            case MSM_CPU_YUPIK: +                mSupportExternalControl = true; +                break; +            default: +                mSupportExternalControl = false; +                break; +            } +            break; +        } + +        close(fd); +    } + +    closedir(dp); +} + +/** Play vibration + * + *  @param effectId:  ID of the predefined effect will be played. If effectId is valid + *                    (non-negative value), the timeoutMs value will be ignored, and the + *                    real playing length will be set in param@playLengtMs and returned + *                    to VibratorService. If effectId is invalid, value in param@timeoutMs + *                    will be used as the play length for playing a constant effect. + *  @param timeoutMs: playing length, non-zero means playing, zero means stop playing. + *  @param playLengthMs: the playing length in ms unit which will be returned to + *                    VibratorService if the request is playing a predefined effect. + *                    The custom_data in periodic is reused for returning the playLengthMs + *                    from kernel space to userspace if the pattern is defined in kernel + *                    driver. It's been defined with following format: + *                       <effect-ID, play-time-in-seconds, play-time-in-milliseconds>. + *                    The effect-ID is used for passing down the predefined effect to + *                    kernel driver, and the rest two parameters are used for returning + *                    back the real playing length from kernel driver. + */ +int InputFFDevice::play(int effectId, uint32_t timeoutMs, long *playLengthMs) { +    struct ff_effect effect; +    struct input_event play; +    int16_t data[CUSTOM_DATA_LEN] = {0, 0, 0}; +    int ret; +#ifdef USE_EFFECT_STREAM +    const struct effect_stream *stream; +#endif + +    /* For QMAA compliance, return OK even if vibrator device doesn't exist */ +    if (mVibraFd == INVALID_VALUE) { +        if (playLengthMs != NULL) +            *playLengthMs = 0; +            return 0; +    } + +    if (timeoutMs != 0) { +        if (mCurrAppId != INVALID_VALUE) { +            ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId)); +            if (ret == -1) { +                ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno); +                goto errout; +            } +            mCurrAppId = INVALID_VALUE; +        } + +        memset(&effect, 0, sizeof(effect)); +        if (effectId != INVALID_VALUE) { +            data[0] = effectId; +            effect.type = FF_PERIODIC; +            effect.u.periodic.waveform = FF_CUSTOM; +            effect.u.periodic.magnitude = mCurrMagnitude; +            effect.u.periodic.custom_data = data; +            effect.u.periodic.custom_len = sizeof(int16_t) * CUSTOM_DATA_LEN; +#ifdef USE_EFFECT_STREAM +            stream = get_effect_stream(effectId); +            if (stream != NULL) { +                effect.u.periodic.custom_data = (int16_t *)stream; +                effect.u.periodic.custom_len = sizeof(*stream); +            } +#endif +        } else { +            effect.type = FF_CONSTANT; +            effect.u.constant.level = mCurrMagnitude; +            effect.replay.length = timeoutMs; +        } + +        effect.id = mCurrAppId; +        effect.replay.delay = 0; + +        ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCSFF, &effect)); +        if (ret == -1) { +            ALOGE("ioctl EVIOCSFF failed, errno = %d", -errno); +            goto errout; +        } + +        mCurrAppId = effect.id; +        if (effectId != INVALID_VALUE && playLengthMs != NULL) { +            *playLengthMs = data[1] * 1000 + data[2]; +#ifdef USE_EFFECT_STREAM +            if (stream != NULL && stream->play_rate_hz != 0) +                *playLengthMs = ((stream->length * 1000) / stream->play_rate_hz) + 1; +#endif +        } + +        play.value = 1; +        play.type = EV_FF; +        play.code = mCurrAppId; +        play.time.tv_sec = 0; +        play.time.tv_usec = 0; +        ret = TEMP_FAILURE_RETRY(write(mVibraFd, (const void*)&play, sizeof(play))); +        if (ret == -1) { +            ALOGE("write failed, errno = %d\n", -errno); +            ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId)); +            if (ret == -1) +                ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno); +            goto errout; +        } +    } else if (mCurrAppId != INVALID_VALUE) { +        ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId)); +        if (ret == -1) { +            ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno); +            goto errout; +        } +        mCurrAppId = INVALID_VALUE; +    } +    return 0; + +errout: +    mCurrAppId = INVALID_VALUE; +    return ret; +} + +int InputFFDevice::on(int32_t timeoutMs) { +    return play(INVALID_VALUE, timeoutMs, NULL); +} + +int InputFFDevice::off() { +    return play(INVALID_VALUE, 0, NULL); +} + +int InputFFDevice::setAmplitude(uint8_t amplitude) { +    int tmp, ret; +    struct input_event ie; + +    /* For QMAA compliance, return OK even if vibrator device doesn't exist */ +    if (mVibraFd == INVALID_VALUE) +        return 0; + +    tmp = amplitude * (STRONG_MAGNITUDE - LIGHT_MAGNITUDE) / 255; +    tmp += LIGHT_MAGNITUDE; +    ie.type = EV_FF; +    ie.code = FF_GAIN; +    ie.value = tmp; + +    ret = TEMP_FAILURE_RETRY(write(mVibraFd, &ie, sizeof(ie))); +    if (ret == -1) { +        ALOGE("write FF_GAIN failed, errno = %d", -errno); +        return ret; +    } + +    mCurrMagnitude = tmp; +    return 0; +} + +int InputFFDevice::playEffect(int effectId, EffectStrength es, long *playLengthMs) { +    switch (es) { +    case EffectStrength::LIGHT: +        mCurrMagnitude = LIGHT_MAGNITUDE; +        break; +    case EffectStrength::MEDIUM: +        mCurrMagnitude = MEDIUM_MAGNITUDE; +        break; +    case EffectStrength::STRONG: +        mCurrMagnitude = STRONG_MAGNITUDE; +        break; +    default: +        return -1; +    } + +    return play(effectId, INVALID_VALUE, playLengthMs); +} + +LedVibratorDevice::LedVibratorDevice() { +    char devicename[PATH_MAX]; +    int fd; + +    mDetected = false; + +    snprintf(devicename, sizeof(devicename), "%s/%s", LED_DEVICE, "activate"); +    fd = TEMP_FAILURE_RETRY(open(devicename, O_RDWR)); +    if (fd < 0) { +        ALOGE("open %s failed, errno = %d", devicename, errno); +        return; +    } + +    mDetected = true; +} + +int LedVibratorDevice::write_value(const char *file, const char *value) { +    int fd; +    int ret; + +    fd = TEMP_FAILURE_RETRY(open(file, O_WRONLY)); +    if (fd < 0) { +        ALOGE("open %s failed, errno = %d", file, errno); +        return -errno; +    } + +    ret = TEMP_FAILURE_RETRY(write(fd, value, strlen(value) + 1)); +    if (ret == -1) { +        ret = -errno; +    } else if (ret != strlen(value) + 1) { +        /* even though EAGAIN is an errno value that could be set +           by write() in some cases, none of them apply here.  So, this return +           value can be clearly identified when debugging and suggests the +           caller that it may try to call vibrator_on() again */ +        ret = -EAGAIN; +    } else { +        ret = 0; +    } + +    errno = 0; +    close(fd); + +    return ret; +} + +int LedVibratorDevice::on(int32_t timeoutMs) { +    char file[PATH_MAX]; +    char value[32]; +    int ret; + +    snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "state"); +    ret = write_value(file, "1"); +    if (ret < 0) +       goto error; + +    snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "duration"); +    snprintf(value, sizeof(value), "%u\n", timeoutMs); +    ret = write_value(file, value); +    if (ret < 0) +       goto error; + +    snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "activate"); +    ret = write_value(file, "1"); +    if (ret < 0) +       goto error; + +    return 0; + +error: +    ALOGE("Failed to turn on vibrator ret: %d\n", ret); +    return ret; +} + +int LedVibratorDevice::off() +{ +    char file[PATH_MAX]; +    int ret; + +    snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "activate"); +    ret = write_value(file, "0"); +    return ret; +} + +ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { +    *_aidl_return = IVibrator::CAP_ON_CALLBACK; + +    if (ledVib.mDetected) { +        *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK; +        ALOGD("QTI Vibrator reporting capabilities: %d", *_aidl_return); +        return ndk::ScopedAStatus::ok(); +    } + +    if (ff.mSupportGain) +        *_aidl_return |= IVibrator::CAP_AMPLITUDE_CONTROL; +    if (ff.mSupportEffects) +        *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK; +    if (ff.mSupportExternalControl) +        *_aidl_return |= IVibrator::CAP_EXTERNAL_CONTROL; + +    ALOGD("QTI Vibrator reporting capabilities: %d", *_aidl_return); +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::off() { +    int ret; + +    ALOGD("QTI Vibrator off"); +    if (ledVib.mDetected) +        ret = ledVib.off(); +    else +        ret = ff.off(); +    if (ret != 0) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, +                                const std::shared_ptr<IVibratorCallback>& callback) { +    int ret; + +    ALOGD("Vibrator on for timeoutMs: %d", timeoutMs); +    if (ledVib.mDetected) +        ret = ledVib.on(timeoutMs); +    else +        ret = ff.on(timeoutMs); + +    if (ret != 0) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + +    if (callback != nullptr) { +        std::thread([=] { +            ALOGD("Starting on on another thread"); +            usleep(timeoutMs * 1000); +            ALOGD("Notifying on complete"); +            if (!callback->onComplete().isOk()) { +                ALOGE("Failed to call onComplete"); +            } +        }).detach(); +    } + +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength es, const std::shared_ptr<IVibratorCallback>& callback, int32_t* _aidl_return) { +    long playLengthMs; +    int ret; + +    if (ledVib.mDetected) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    ALOGD("Vibrator perform effect %d", effect); + +    if (effect < Effect::CLICK || +            effect > Effect::HEAVY_CLICK) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs); +    if (ret != 0) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + +    if (callback != nullptr) { +        std::thread([=] { +            ALOGD("Starting perform on another thread"); +            usleep(playLengthMs * 1000); +            ALOGD("Notifying perform complete"); +            callback->onComplete(); +        }).detach(); +    } + +    *_aidl_return = playLengthMs; +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) { +    if (ledVib.mDetected) +        return ndk::ScopedAStatus::ok(); + +    *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD, +                     Effect::POP, Effect::HEAVY_CLICK}; + +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { +    uint8_t tmp; +    int ret; + +    if (ledVib.mDetected) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    ALOGD("Vibrator set amplitude: %f", amplitude); + +    if (amplitude <= 0.0f || amplitude > 1.0f) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); + +    if (ff.mInExternalControl) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    tmp = (uint8_t)(amplitude * 0xff); +    ret = ff.setAmplitude(tmp); +    if (ret != 0) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { +    if (ledVib.mDetected) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    ALOGD("Vibrator set external control: %d", enabled); +    if (!ff.mSupportExternalControl) +        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + +    ff.mInExternalControl = enabled; +    return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs  __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive __unused, +                                                  int32_t* durationMs __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite __unused, +                                     const std::shared_ptr<IVibratorCallback>& callback __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id __unused, Effect effect __unused, +                                            EffectStrength strength __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id __unused) { +    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +}  // namespace vibrator +}  // namespace hardware +}  // namespace android +}  // namespace aidl + diff --git a/vibrator/excluded-input-devices.xml b/vibrator/excluded-input-devices.xml new file mode 100644 index 0000000..dfea562 --- /dev/null +++ b/vibrator/excluded-input-devices.xml @@ -0,0 +1,32 @@ +<?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"/> +</devices> diff --git a/vibrator/include/Vibrator.h b/vibrator/include/Vibrator.h new file mode 100644 index 0000000..e0694ca --- /dev/null +++ b/vibrator/include/Vibrator.h @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#pragma once + +#include <aidl/android/hardware/vibrator/BnVibrator.h> + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +class InputFFDevice { +public: +    InputFFDevice(); +    int playEffect(int effectId, EffectStrength es, 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 Vibrator : public BnVibrator { +public: +    class InputFFDevice ff; +    class LedVibratorDevice ledVib; +    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; +}; + +}  // namespace vibrator +}  // namespace hardware +}  // namespace android +}  // namespace aidl diff --git a/vibrator/service.cpp b/vibrator/service.cpp new file mode 100644 index 0000000..ff9706d --- /dev/null +++ b/vibrator/service.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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. + */ + +#define LOG_TAG "vendor.qti.hardware.vibrator.service.xiaomi_holi" + +#include <android-base/logging.h> +#include <android/binder_manager.h> +#include <android/binder_process.h> + +#include "Vibrator.h" + +using aidl::android::hardware::vibrator::Vibrator; + +int main() { +    ABinderProcess_setThreadPoolMaxThreadCount(0); +    std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>(); + +    const std::string instance = std::string() + Vibrator::descriptor + "/default"; +    binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str()); +    CHECK(status == STATUS_OK); + +    ABinderProcess_joinThreadPool(); +    return EXIT_FAILURE;  // should not reach +} diff --git a/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.rc b/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.rc new file mode 100644 index 0000000..1293483 --- /dev/null +++ b/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.rc @@ -0,0 +1,4 @@ +service vendor.qti.vibrator.xiaomi_holi /vendor/bin/hw/vendor.qti.hardware.vibrator.service.xiaomi_holi +    class hal +    user system +    group system input diff --git a/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.xml b/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.xml new file mode 100644 index 0000000..df29ada --- /dev/null +++ b/vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.xml @@ -0,0 +1,33 @@ +<!-- Copyright (c) 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. +--> +<manifest version="1.0" type="device"> +    <hal format="aidl"> +        <name>android.hardware.vibrator</name> +        <fqname>IVibrator/default</fqname> +    </hal> +</manifest>  | 
