aboutsummaryrefslogtreecommitdiff
path: root/vibrator
diff options
context:
space:
mode:
authorkleidione Freitas <kleidione@gmail.com>2022-03-24 09:16:43 -0300
committerkleidione <kleidione@gmail.com>2022-11-09 17:29:16 -0300
commit44d5c9e2cf9f1ce0670be5bedd1e415cd5c3e739 (patch)
tree4516fedba0c65fda9e795d8737d08a7746d41e40 /vibrator
parent15eeafbf239f393fcb6ed1a719398e5b7bbd6a19 (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.bp42
-rw-r--r--vibrator/Vibrator.cpp587
-rw-r--r--vibrator/excluded-input-devices.xml32
-rw-r--r--vibrator/include/Vibrator.h96
-rw-r--r--vibrator/service.cpp50
-rw-r--r--vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.rc4
-rw-r--r--vibrator/vendor.qti.hardware.vibrator.service.xiaomi_holi.xml33
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>