Merge changes from topic "AK3_porting"

* changes:
  vibrator: cs40l26: Sync the HAL patches delta from main to device folder
  vibrator: enable f0 and disable redc compensation
This commit is contained in:
TreeHugger Robot 2023-01-31 04:48:45 +00:00 committed by Android (Google) Code Review
commit 2c9072d3d2
11 changed files with 185 additions and 252 deletions

View file

@ -206,3 +206,9 @@ PRODUCT_VENDOR_PROPERTIES += \
# Disable camera DPM
PRODUCT_PROPERTY_OVERRIDES += \
vendor.camera.debug.force_dpm_on=0
# Vibrator HAL
PRODUCT_VENDOR_PROPERTIES += \
ro.vendor.vibrator.hal.supported_primitives=243 \
ro.vendor.vibrator.hal.f0.comp.enabled=1 \
ro.vendor.vibrator.hal.redc.comp.enabled=0 \

View file

@ -76,16 +76,3 @@ cc_binary {
shared_libs: ["android.hardware.vibrator-impl.cs40l26-akita"],
proprietary: true,
}
cc_binary {
name: "android.hardware.vibrator-service.cs40l26-dual-akita",
defaults: ["VibratorHalCs40l26BinaryDefaultsAkita"],
init_rc: ["android.hardware.vibrator-service.cs40l26-dual-akita.rc"],
vintf_fragments: ["android.hardware.vibrator-service.cs40l26-dual-akita.xml"],
srcs: ["service.cpp"],
shared_libs: ["android.hardware.vibrator-impl.cs40l26-akita"],
cflags: ["-DVIBRATOR_NAME=\"dual\""],
proprietary: true,
}

View file

@ -94,6 +94,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
bool setMinOnOffInterval(uint32_t value) override { return set(value, &mMinOnOffInterval); }
// TODO(b/234338136): Need to add the force feedback HW API test cases
bool setFFGain(int fd, uint16_t value) override {
ATRACE_NAME(StringPrintf("%s %d%%", __func__, value).c_str());
struct input_event gain = {
.type = EV_FF,
.code = FF_GAIN,
@ -105,6 +106,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
return true;
}
bool setFFEffect(int fd, struct ff_effect *effect, uint16_t timeoutMs) override {
ATRACE_NAME(StringPrintf("%s %dms", __func__, timeoutMs).c_str());
if (((*effect).replay.length != timeoutMs) || (ioctl(fd, EVIOCSFF, effect) < 0)) {
ALOGE("setFFEffect fail");
return false;
@ -113,6 +115,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
}
}
bool setFFPlay(int fd, int8_t index, bool value) override {
ATRACE_NAME(StringPrintf("%s index:%d %s", __func__, index, value ? "on" : "off").c_str());
struct input_event play = {
.type = EV_FF,
.code = static_cast<uint16_t>(index),
@ -125,6 +128,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
}
}
bool getHapticAlsaDevice(int *card, int *device) override {
ATRACE_NAME(__func__);
std::string line;
std::ifstream myfile(PROC_SND_PCM);
if (myfile.is_open()) {
@ -144,6 +148,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
return false;
}
bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) override {
ATRACE_NAME(StringPrintf("%s %s", __func__, enable ? "enable" : "disable").c_str());
int ret = 0;
if (enable) {
@ -181,6 +186,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
}
bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect,
uint32_t *outEffectIndex, int *status) override {
ATRACE_NAME(__func__);
(*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t);
delete[] ((*effect).u.periodic.custom_data);
(*effect).u.periodic.custom_data = new int16_t[(*effect).u.periodic.custom_len]{0x0000};
@ -214,13 +220,17 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
return true;
}
bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector<ff_effect> *effect) override {
ATRACE_NAME(__func__);
uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0;
if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) {
ALOGE("Invalid waveform index for OWT erase: %d", effectIndex);
return false;
}
// Turn off the waiting time for SVC init phase to complete since chip
// should already under STOP state
setMinOnOffInterval(0);
// Do erase flow
if (effectIndex < WAVEFORM_MAX_INDEX) {
/* Normal situation. Only erase the effect which we just played. */
if (ioctl(fd, EVIOCRMFF, effectIndex) < 0) {
@ -248,6 +258,8 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
(*effect)[i].id = -1;
}
}
// Turn on the waiting time for SVC init phase to complete
setMinOnOffInterval(Vibrator::MIN_ON_OFF_INTERVAL_US);
return true;
}
@ -335,6 +347,16 @@ class HwCal : public Vibrator::HwCal, private HwCalBase {
bool getSupportedPrimitives(uint32_t *value) override {
return getProperty("supported_primitives", value, (uint32_t)0);
}
bool isF0CompEnabled() override {
bool value;
getProperty("f0.comp.enabled", &value, true);
return value;
}
bool isRedcCompEnabled() override {
bool value;
getProperty("redc.comp.enabled", &value, true);
return value;
}
void debug(int fd) override { HwCalBase::debug(fd); }
};

View file

@ -35,10 +35,22 @@
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "Vibrator"
#endif
namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {
#ifdef HAPTIC_TRACE
#define HAPTICS_TRACE(...) ALOGD(__VA_ARGS__)
#else
#define HAPTICS_TRACE(...)
#endif
static constexpr uint8_t FF_CUSTOM_DATA_LEN = 2;
static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_COMP = 2044; // (COMPOSE_SIZE_MAX + 1) * 8 + 4
static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_PWLE = 2302;
@ -50,7 +62,6 @@ static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50;
static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time
static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
static constexpr uint32_t MAX_TIME_MS = UINT16_MAX;
@ -111,11 +122,6 @@ static uint16_t amplitudeToScale(float amplitude, float maximum) {
return std::round(ratio);
}
enum class AlwaysOnId : uint32_t {
GPIO_RISE,
GPIO_FALL,
};
enum WaveformBankID : uint8_t {
RAM_WVFRM_BANK,
ROM_WVFRM_BANK,
@ -144,8 +150,8 @@ enum WaveformIndex : uint16_t {
WAVEFORM_PWLE,
/*
* Refer to <linux/input.h>, the WAVEFORM_MAX_INDEX must not exceed 96.
* #define FF_GAIN 0x60 // 96 in decimal
* #define FF_MAX_EFFECTS FF_GAIN
* #define FF_GAIN 0x60 // 96 in decimal
* #define FF_MAX_EFFECTS FF_GAIN
*/
WAVEFORM_MAX_INDEX,
};
@ -159,6 +165,8 @@ enum vibe_state {
VIBE_STATE_ASP,
};
std::mutex mActiveId_mutex; // protects mActiveId
static int min(int x, int y) {
return x < y ? x : y;
}
@ -182,6 +190,7 @@ struct dspmem_chunk {
};
static dspmem_chunk *dspmem_chunk_create(void *data, int size) {
HAPTICS_TRACE(" dspmem_chunk_create(data, size:%d)", size);
auto ch = new dspmem_chunk{
.head = reinterpret_cast<uint8_t *>(data),
.current = reinterpret_cast<uint8_t *>(data),
@ -192,14 +201,17 @@ static dspmem_chunk *dspmem_chunk_create(void *data, int size) {
}
static bool dspmem_chunk_end(struct dspmem_chunk *ch) {
HAPTICS_TRACE(" dspmem_chunk_end(ch)");
return ch->current == ch->max;
}
static int dspmem_chunk_bytes(struct dspmem_chunk *ch) {
HAPTICS_TRACE(" dspmem_chunk_bytes(ch)");
return ch->bytes;
}
static int dspmem_chunk_write(struct dspmem_chunk *ch, int nbits, uint32_t val) {
HAPTICS_TRACE(" dspmem_chunk_write(ch, nbits:%d, val:%u)", nbits, val);
int nwrite, i;
nwrite = min(24 - ch->cachebits, nbits);
@ -227,6 +239,7 @@ static int dspmem_chunk_write(struct dspmem_chunk *ch, int nbits, uint32_t val)
}
static int dspmem_chunk_flush(struct dspmem_chunk *ch) {
HAPTICS_TRACE(" dspmem_chunk_flush(ch)");
if (!ch->cachebits)
return 0;
@ -306,7 +319,7 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
mFfEffects.resize(WAVEFORM_MAX_INDEX);
mEffectDurations.resize(WAVEFORM_MAX_INDEX);
mEffectDurations = {
1000, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000,
1000, 100, 12, 1000, 300, 130, 150, 500, 100, 5, 12, 1000, 1000, 1000,
}; /* 11+3 waveforms. The duration must < UINT16_MAX */
uint8_t effectIndex;
@ -380,9 +393,10 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
} else {
ALOGD("Unsupported calibration version: %u!", calVer);
}
HAPTICS_TRACE("Vibrator(hwapi, hwcal:%u)", calVer);
mHwApi->setF0CompEnable(true);
mHwApi->setRedcCompEnable(true);
mHwApi->setF0CompEnable(mHwCal->isF0CompEnabled());
mHwApi->setRedcCompEnable(mHwCal->isRedcCompEnabled());
mIsUnderExternalControl = false;
@ -409,11 +423,12 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
}
ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
HAPTICS_TRACE("getCapabilities(_aidl_return)");
ATRACE_NAME("Vibrator::getCapabilities");
int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_ALWAYS_ON_CONTROL |
IVibrator::CAP_GET_RESONANT_FREQUENCY | IVibrator::CAP_GET_Q_FACTOR;
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
IVibrator::CAP_GET_Q_FACTOR;
if (hasHapticAlsaDevice()) {
ret |= IVibrator::CAP_EXTERNAL_CONTROL;
} else {
@ -430,34 +445,44 @@ ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
}
ndk::ScopedAStatus Vibrator::off() {
HAPTICS_TRACE("off()");
ATRACE_NAME("Vibrator::off");
if (mActiveId < 0) {
ALOGD("Vibrator is already off");
return ndk::ScopedAStatus::ok();
bool ret{true};
const std::scoped_lock<std::mutex> lock(mActiveId_mutex);
if (mActiveId >= 0) {
/* Stop the active effect. */
if (!mHwApi->setFFPlay(mInputFd, mActiveId, false)) {
ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno));
ret = false;
}
if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) &&
(!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) {
ALOGE("Failed to clean up the composed effect %d", mActiveId);
ret = false;
}
} else {
ALOGV("Vibrator is already off");
}
/* Stop the active effect. */
if (!mHwApi->setFFPlay(mInputFd, mActiveId, false)) {
ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno));
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) &&
(!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
mActiveId = -1;
setGlobalAmplitude(false);
if (mF0Offset) {
mHwApi->setF0Offset(0);
}
return ndk::ScopedAStatus::ok();
if (ret) {
return ndk::ScopedAStatus::ok();
} else {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
}
ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
const std::shared_ptr<IVibratorCallback> &callback) {
ATRACE_NAME("Vibrator::on");
ATRACE_NAME(StringPrintf("Vibrator::on %dms", timeoutMs).c_str());
HAPTICS_TRACE("on(timeoutMs:%u, callback)", timeoutMs);
if (timeoutMs > MAX_TIME_MS) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
@ -477,17 +502,23 @@ ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback> &callback,
int32_t *_aidl_return) {
ATRACE_NAME("Vibrator::perform");
ATRACE_NAME(StringPrintf("Vibrator::perform %s,%s", toString(effect).c_str(),
toString(strength).c_str())
.c_str());
HAPTICS_TRACE("perform(effect:%s, strength:%s, callback, _aidl_return)",
toString(effect).c_str(), toString(strength).c_str());
return performEffect(effect, strength, callback, _aidl_return);
}
ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
HAPTICS_TRACE("getSupportedEffects(_aidl_return)");
*_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
Effect::DOUBLE_CLICK};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
HAPTICS_TRACE("setAmplitude(amplitude:%f)", amplitude);
ATRACE_NAME("Vibrator::setAmplitude");
if (amplitude <= 0.0f || amplitude > 1.0f) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@ -502,6 +533,7 @@ ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
}
ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
HAPTICS_TRACE("setExternalControl(enabled:%u)", enabled);
ATRACE_NAME("Vibrator::setExternalControl");
setGlobalAmplitude(enabled);
@ -520,24 +552,28 @@ ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
}
ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) {
HAPTICS_TRACE("getCompositionDelayMax(maxDelayMs)");
ATRACE_NAME("Vibrator::getCompositionDelayMax");
*maxDelayMs = COMPOSE_DELAY_MAX_MS;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) {
HAPTICS_TRACE("getCompositionSizeMax(maxSize)");
ATRACE_NAME("Vibrator::getCompositionSizeMax");
*maxSize = COMPOSE_SIZE_MAX;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> *supported) {
HAPTICS_TRACE("getSupportedPrimitives(supported)");
*supported = mSupportedPrimitives;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
int32_t *durationMs) {
HAPTICS_TRACE("getPrimitiveDuration(primitive:%s, durationMs)", toString(primitive).c_str());
ndk::ScopedAStatus status;
uint32_t effectIndex;
if (primitive != CompositePrimitive::NOOP) {
@ -555,7 +591,8 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite,
const std::shared_ptr<IVibratorCallback> &callback) {
ATRACE_NAME("Vibrator::compose");
ATRACE_NAME(StringPrintf("Vibrator::compose size=%zu", composite.size()).c_str());
HAPTICS_TRACE("compose(composite, callback)");
uint16_t size;
uint16_t nextEffectDelay;
@ -637,17 +674,16 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback) {
HAPTICS_TRACE("on(timeoutMs:%u, effectIndex:%u, ch, callback)", timeoutMs, effectIndex);
ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
if (effectIndex >= FF_MAX_EFFECTS) {
ALOGE("Invalid waveform index %d", effectIndex);
status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
goto end;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) {
ALOGE("Previous vibration pending: prev: %d, curr: %d", mActiveId, effectIndex);
status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
goto end;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
if (ch) {
@ -684,26 +720,24 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem
if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex],
static_cast<uint16_t>(timeoutMs))) {
ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno));
status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
goto end;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
}
const std::scoped_lock<std::mutex> lock(mActiveId_mutex);
mActiveId = effectIndex;
/* Play the event now. */
if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) {
ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno));
status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
goto end;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
end:
return status;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
HAPTICS_TRACE("setEffectAmplitude(amplitude:%f, maximum:%f)", amplitude, maximum);
uint16_t scale = amplitudeToScale(amplitude, maximum);
if (!mHwApi->setFFGain(mInputFd, scale)) {
ALOGE("Failed to set the gain to %u (%d): %s", scale, errno, strerror(errno));
@ -713,6 +747,7 @@ ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum)
}
ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
HAPTICS_TRACE("setGlobalAmplitude(set:%u)", set);
uint8_t amplitude = set ? roundf(mLongEffectScale * mLongEffectVol[1]) : VOLTAGE_SCALE_MAX;
if (!set) {
mLongEffectScale = 1.0; // Reset the scale for the later new effect.
@ -720,57 +755,27 @@ ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX);
}
ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
*_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
ndk::ScopedAStatus status;
uint32_t effectIndex;
uint32_t timeMs;
uint32_t volLevel;
uint16_t scale;
status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
if (!status.isOk()) {
return status;
}
scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX);
switch (static_cast<AlwaysOnId>(id)) {
case AlwaysOnId::GPIO_RISE:
// mHwApi->setGpioRiseIndex(effectIndex);
// mHwApi->setGpioRiseScale(scale);
return ndk::ScopedAStatus::ok();
case AlwaysOnId::GPIO_FALL:
// mHwApi->setGpioFallIndex(effectIndex);
// mHwApi->setGpioFallScale(scale);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> * /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
switch (static_cast<AlwaysOnId>(id)) {
case AlwaysOnId::GPIO_RISE:
// mHwApi->setGpioRiseIndex(0);
return ndk::ScopedAStatus::ok();
case AlwaysOnId::GPIO_FALL:
// mHwApi->setGpioFallIndex(0);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/,
EffectStrength /*strength*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
HAPTICS_TRACE("getResonantFrequency(resonantFreqHz)");
*resonantFreqHz = mResonantFrequency;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
HAPTICS_TRACE("getQFactor(qFactor)");
std::string caldata{8, '0'};
if (!mHwCal->getQ(&caldata)) {
ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno));
@ -782,6 +787,7 @@ ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
}
ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
HAPTICS_TRACE("getFrequencyResolution(freqResolutionHz)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
@ -793,6 +799,7 @@ ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
}
ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
HAPTICS_TRACE("getFrequencyMinimum(freqMinimumHz)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
@ -837,11 +844,8 @@ void Vibrator::createPwleMaxLevelLimitMap() {
pwleMaxLevelLimitMapIdx =
(itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ;
// FixLater: avoid floating point loop counters
// NOLINTBEGIN(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
for (float xp = x0; xp < (x1 + PWLE_FREQUENCY_RESOLUTION_HZ);
xp += PWLE_FREQUENCY_RESOLUTION_HZ) {
// NOLINTEND(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
float yp = y0 + ratioOfXY * (xp - x0);
pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx++] = yp;
@ -925,6 +929,7 @@ void Vibrator::createBandwidthAmplitudeMap() {
}
ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
HAPTICS_TRACE("getBandwidthAmplitudeMap(_aidl_return)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
@ -942,6 +947,7 @@ ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_
}
ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
HAPTICS_TRACE("getPwlePrimitiveDurationMax(durationMs)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
@ -953,6 +959,7 @@ ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
}
ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
HAPTICS_TRACE("getPwleCompositionSizeMax(maxSize)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
@ -964,6 +971,7 @@ ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
}
ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
HAPTICS_TRACE("getSupportedBraking(supported)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
@ -978,6 +986,7 @@ ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported
static void resetPreviousEndAmplitudeEndFrequency(float *prevEndAmplitude,
float *prevEndFrequency) {
HAPTICS_TRACE(" resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency)");
const float reset = -1.0;
*prevEndAmplitude = reset;
*prevEndFrequency = reset;
@ -989,6 +998,10 @@ static void incrementIndex(int *index) {
static void constructPwleSegment(dspmem_chunk *ch, uint16_t delay, uint16_t amplitude,
uint16_t frequency, uint8_t flags, uint32_t vbemfTarget = 0) {
HAPTICS_TRACE(
" constructPwleSegment(ch, delay:%u, amplitude:%u, frequency:%u, flags:%u"
", vbemfTarget:%u)",
delay, amplitude, frequency, flags, vbemfTarget);
dspmem_chunk_write(ch, 16, delay);
dspmem_chunk_write(ch, 12, amplitude);
dspmem_chunk_write(ch, 12, frequency);
@ -1001,6 +1014,8 @@ static void constructPwleSegment(dspmem_chunk *ch, uint16_t delay, uint16_t ampl
static int constructActiveSegment(dspmem_chunk *ch, int duration, float amplitude, float frequency,
bool chirp) {
HAPTICS_TRACE(" constructActiveSegment(ch, duration:%d, amplitude:%f, frequency:%f)",
duration, amplitude, frequency);
uint16_t delay = 0;
uint16_t amp = 0;
uint16_t freq = 0;
@ -1020,6 +1035,8 @@ static int constructActiveSegment(dspmem_chunk *ch, int duration, float amplitud
}
static int constructBrakingSegment(dspmem_chunk *ch, int duration, Braking brakingType) {
HAPTICS_TRACE(" constructBrakingSegment(ch, duration:%d, brakingType:%s)", duration,
toString(brakingType).c_str());
uint16_t delay = 0;
uint16_t freq = 0;
uint8_t flags = 0x00;
@ -1037,6 +1054,7 @@ static int constructBrakingSegment(dspmem_chunk *ch, int duration, Braking braki
}
static void updateWLength(dspmem_chunk *ch, uint32_t totalDuration) {
HAPTICS_TRACE(" updateWLength(ch, totalDuration:%u)", totalDuration);
totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */
totalDuration |= WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */
*(ch->head + 0) = (totalDuration >> 24) & 0xFF;
@ -1046,13 +1064,15 @@ static void updateWLength(dspmem_chunk *ch, uint32_t totalDuration) {
}
static void updateNSection(dspmem_chunk *ch, int segmentIdx) {
HAPTICS_TRACE(" updateNSection(ch, segmentIdx:%u)", segmentIdx);
*(ch->head + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */
*(ch->head + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */
}
ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
const std::shared_ptr<IVibratorCallback> &callback) {
ATRACE_NAME("Vibrator::composePwle");
ATRACE_NAME(StringPrintf("Vibrator::composePwle size=%zu", composite.size()).c_str());
HAPTICS_TRACE("composePwle(composite, callback)");
int32_t capabilities;
Vibrator::getCapabilities(&capabilities);
@ -1185,10 +1205,12 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
}
bool Vibrator::isUnderExternalControl() {
HAPTICS_TRACE("isUnderExternalControl()");
return mIsUnderExternalControl;
}
binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
HAPTICS_TRACE("dump(fd:%d, args, numArgs:%u)", fd, numArgs);
if (fd < 0) {
ALOGE("Called debug() with invalid fd.");
return STATUS_OK;
@ -1248,6 +1270,7 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
}
bool Vibrator::hasHapticAlsaDevice() {
HAPTICS_TRACE("hasHapticAlsaDevice()");
// We need to call findHapticAlsaDevice once only. Calling in the
// constructor is too early in the boot process and the pcm file contents
// are empty. Hence we make the call here once only right before we need to.
@ -1267,6 +1290,10 @@ bool Vibrator::hasHapticAlsaDevice() {
ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
uint32_t *outEffectIndex, uint32_t *outTimeMs,
uint32_t *outVolLevel) {
HAPTICS_TRACE(
"getSimpleDetails(effect:%s, strength:%s, outEffectIndex, outTimeMs"
", outVolLevel)",
toString(effect).c_str(), toString(strength).c_str());
uint32_t effectIndex;
uint32_t timeMs;
float intensity;
@ -1317,6 +1344,8 @@ ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength stre
ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
uint32_t *outTimeMs, dspmem_chunk *outCh) {
HAPTICS_TRACE("getCompoundDetails(effect:%s, strength:%s, outTimeMs, outCh)",
toString(effect).c_str(), toString(strength).c_str());
ndk::ScopedAStatus status;
uint32_t timeMs = 0;
uint32_t thisEffectIndex;
@ -1370,6 +1399,7 @@ ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength st
ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
uint32_t *outEffectIndex) {
HAPTICS_TRACE("getPrimitiveDetails(primitive:%s, outEffectIndex)", toString(primitive).c_str());
uint32_t effectIndex;
uint32_t primitiveBit = 1 << int32_t(primitive);
if ((primitiveBit & mSupportedPrimitivesBits) == 0x0) {
@ -1415,6 +1445,8 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback> &callback,
int32_t *outTimeMs) {
HAPTICS_TRACE("performEffect(effect:%s, strength:%s, callback, outTimeMs)",
toString(effect).c_str(), toString(strength).c_str());
ndk::ScopedAStatus status;
uint32_t effectIndex;
uint32_t timeMs = 0;
@ -1454,20 +1486,38 @@ exit:
ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback) {
HAPTICS_TRACE("performEffect(effectIndex:%u, volLevel:%u, ch, callback)", effectIndex,
volLevel);
setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
return on(MAX_TIME_MS, effectIndex, ch, callback);
}
void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
HAPTICS_TRACE("waitForComplete(callback)");
if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) {
ALOGW("Failed to get state \"Haptic\"");
}
ATRACE_BEGIN("Vibrating");
mHwApi->pollVibeState(VIBE_STATE_STOPPED);
ATRACE_END();
if (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) {
mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects);
const std::scoped_lock<std::mutex> lock(mActiveId_mutex);
uint32_t effectCount = WAVEFORM_MAX_PHYSICAL_INDEX;
if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) &&
(!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) {
ALOGE("Failed to clean up the composed effect %d", mActiveId);
} else {
ALOGD("waitForComplete: Vibrator is already off");
}
mHwApi->getEffectCount(&effectCount);
// Do waveform number checking
if ((effectCount > WAVEFORM_MAX_PHYSICAL_INDEX) &&
(!mHwApi->eraseOwtEffect(mInputFd, WAVEFORM_MAX_INDEX, &mFfEffects))) {
ALOGE("Failed to forcibly clean up all composed effect");
}
mActiveId = -1;
if (callback) {
@ -1479,6 +1529,8 @@ void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
}
uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) {
HAPTICS_TRACE("intensityToVolLevel(intensity:%f, effectIndex:%u)", intensity, effectIndex);
uint32_t volLevel;
auto calc = [](float intst, std::array<uint32_t, 2> v) -> uint32_t {
return std::lround(intst * (v[1] - v[0])) + v[0];

View file

@ -16,6 +16,7 @@
#pragma once
#include <aidl/android/hardware/vibrator/BnVibrator.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <linux/input.h>
#include <tinyalsa/asoundlib.h>
@ -29,6 +30,8 @@ namespace android {
namespace hardware {
namespace vibrator {
using ::android::base::StringPrintf;
class Vibrator : public BnVibrator {
public:
// APIs for interfacing with the kernel driver.
@ -114,6 +117,10 @@ class Vibrator : public BnVibrator {
virtual bool isChirpEnabled() = 0;
// Obtains the supported primitive effects.
virtual bool getSupportedPrimitives(uint32_t *value) = 0;
// Checks if the f0 compensation feature needs to be enabled.
virtual bool isF0CompEnabled() = 0;
// Checks if the redc compensation feature needs to be enabled.
virtual bool isRedcCompEnabled() = 0;
// Emit diagnostic information to the given file.
virtual void debug(int fd) = 0;
};
@ -154,6 +161,9 @@ class Vibrator : public BnVibrator {
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
// SVC initialization time
static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500;
private:
ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback);

View file

@ -1,5 +1,5 @@
on property:vendor.all.modules.ready=1
wait /sys/bus/i2c/devices/6-0043/calibration/redc_cal_time_ms
wait /sys/bus/i2c/devices/5-0043/calibration/redc_cal_time_ms
mkdir /mnt/vendor/persist/haptics 0770 system system
chmod 770 /mnt/vendor/persist/haptics

View file

@ -1,74 +0,0 @@
on property:vendor.all.modules.ready=1
wait /sys/bus/i2c/devices/6-0042/calibration/redc_cal_time_ms
mkdir /mnt/vendor/persist/haptics 0770 system system
chmod 770 /mnt/vendor/persist/haptics
chmod 440 /mnt/vendor/persist/haptics/cs40l26_dual.cal
chown system system /mnt/vendor/persist/haptics
chown system system /mnt/vendor/persist/haptics/cs40l26_dual.cal
chown system system /sys/bus/i2c/devices/6-0042/calibration/f0_stored
chown system system /sys/bus/i2c/devices/6-0042/calibration/q_stored
chown system system /sys/bus/i2c/devices/6-0042/calibration/redc_stored
chown system system /sys/bus/i2c/devices/6-0042/default/vibe_state
chown system system /sys/bus/i2c/devices/6-0042/default/num_waves
chown system system /sys/bus/i2c/devices/6-0042/default/f0_offset
chown system system /sys/bus/i2c/devices/6-0042/default/owt_free_space
chown system system /sys/bus/i2c/devices/6-0042/default/f0_comp_enable
chown system system /sys/bus/i2c/devices/6-0042/default/redc_comp_enable
chown system system /sys/bus/i2c/devices/6-0042/default/delay_before_stop_playback_us
chown system system /sys/bus/i2c/devices/5-0042/calibration/f0_stored
chown system system /sys/bus/i2c/devices/5-0042/calibration/q_stored
chown system system /sys/bus/i2c/devices/5-0042/calibration/redc_stored
chown system system /sys/bus/i2c/devices/5-0042/default/vibe_state
chown system system /sys/bus/i2c/devices/5-0042/default/num_waves
chown system system /sys/bus/i2c/devices/5-0042/default/f0_offset
chown system system /sys/bus/i2c/devices/5-0042/default/owt_free_space
chown system system /sys/bus/i2c/devices/5-0042/default/f0_comp_enable
chown system system /sys/bus/i2c/devices/5-0042/default/redc_comp_enable
chown system system /sys/bus/i2c/devices/5-0042/default/delay_before_stop_playback_us
chown system system /sys/bus/i2c/devices/4-0042/calibration/f0_stored
chown system system /sys/bus/i2c/devices/4-0042/calibration/q_stored
chown system system /sys/bus/i2c/devices/4-0042/calibration/redc_stored
chown system system /sys/bus/i2c/devices/4-0042/default/vibe_state
chown system system /sys/bus/i2c/devices/4-0042/default/num_waves
chown system system /sys/bus/i2c/devices/4-0042/default/f0_offset
chown system system /sys/bus/i2c/devices/4-0042/default/owt_free_space
chown system system /sys/bus/i2c/devices/4-0042/default/f0_comp_enable
chown system system /sys/bus/i2c/devices/4-0042/default/redc_comp_enable
chown system system /sys/bus/i2c/devices/4-0042/default/delay_before_stop_playback_us
enable vendor.vibrator.cs40l26-dual
service vendor.vibrator.cs40l26-dual /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-dual-akita
class hal
user system
group system input
setenv INPUT_EVENT_NAME cs40l26_dual_input
setenv INPUT_EVENT_PATH /dev/input/event*
setenv PROPERTY_PREFIX ro.vendor.vibrator.hal.
setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26_dual.cal
setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/
setenv HWAPI_DEBUG_NODES "
6-0042/
5-0042/
4-0042/
"
setenv HWAPI_DEBUG_PATHS "
calibration/f0_stored
calibration/redc_stored
calibration/q_stored
default/vibe_state
default/num_waves
default/f0_offset
default/owt_free_space
default/f0_comp_enable
default/redc_comp_enable
default/delay_before_stop_playback_us
"
disabled

View file

@ -1,7 +0,0 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.vibrator</name>
<version>2</version>
<fqname>IVibrator/dual</fqname>
</hal>
</manifest>

View file

@ -1,7 +0,0 @@
PRODUCT_PACKAGES += \
android.hardware.vibrator-service.cs40l26-akita \
android.hardware.vibrator-service.cs40l26-dual-akita
BOARD_SEPOLICY_DIRS += \
hardware/google/pixel-sepolicy/vibrator/common \
device/google/akita-sepolicy/vibrator/cs40l26

View file

@ -63,6 +63,8 @@ class MockCal : public ::aidl::android::hardware::vibrator::Vibrator::HwCal {
MOCK_METHOD1(getSupportedPrimitives, bool(uint32_t *value));
MOCK_METHOD1(getDeviceMass, bool(float *value));
MOCK_METHOD1(getLocCoeff, bool(float *value));
MOCK_METHOD0(isF0CompEnabled, bool());
MOCK_METHOD0(isRedcCompEnabled, bool());
MOCK_METHOD1(debug, void(int fd));
~MockCal() override { destructor(); };

View file

@ -298,6 +298,8 @@ class VibratorTest : public Test {
EXPECT_CALL(*mMockCal, getLongVolLevels(_)).Times(times);
EXPECT_CALL(*mMockCal, isChirpEnabled()).Times(times);
EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).Times(times);
EXPECT_CALL(*mMockCal, isF0CompEnabled()).Times(times);
EXPECT_CALL(*mMockCal, isRedcCompEnabled()).Times(times);
EXPECT_CALL(*mMockCal, debug(_)).Times(times);
}
@ -350,7 +352,9 @@ TEST_F(VibratorTest, Constructor) {
volGet = EXPECT_CALL(*mMockCal, getLongVolLevels(_)).WillOnce(DoDefault());
}
EXPECT_CALL(*mMockCal, isF0CompEnabled()).WillOnce(Return(true));
EXPECT_CALL(*mMockApi, setF0CompEnable(true)).WillOnce(Return(true));
EXPECT_CALL(*mMockCal, isRedcCompEnabled()).WillOnce(Return(true));
EXPECT_CALL(*mMockApi, setRedcCompEnable(true)).WillOnce(Return(true));
EXPECT_CALL(*mMockCal, isChirpEnabled()).WillOnce(Return(true));
@ -379,6 +383,8 @@ TEST_F(VibratorTest, on) {
}
TEST_F(VibratorTest, off) {
Sequence s1;
EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)).InSequence(s1).WillOnce(DoDefault());
EXPECT_TRUE(mVibrator->off().isOk());
}
@ -547,26 +553,6 @@ TEST_P(EffectsTest, perform) {
}
}
TEST_P(EffectsTest, alwaysOnEnable) {
// No real function now in P22+
auto param = GetParam();
auto effect = std::get<0>(param);
auto strength = std::get<1>(param);
auto scale = EFFECT_SCALE.find(param);
bool supported = (scale != EFFECT_SCALE.end());
if (supported) {
// Do nothing
}
ndk::ScopedAStatus status = mVibrator->alwaysOnEnable(0, effect, strength);
if (supported) {
EXPECT_EQ(EX_NONE, status.getExceptionCode());
} else {
EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
}
}
const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
ndk::enum_range<Effect>().end()};
const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
@ -692,50 +678,6 @@ const std::vector<ComposeParam> kComposeParams = {
INSTANTIATE_TEST_CASE_P(VibratorTests, ComposeTest,
ValuesIn(kComposeParams.begin(), kComposeParams.end()),
ComposeTest::PrintParam);
class AlwaysOnTest : public VibratorTest, public WithParamInterface<int32_t> {
public:
static auto PrintParam(const TestParamInfo<ParamType> &info) {
return std::to_string(info.param);
}
};
TEST_P(AlwaysOnTest, alwaysOnEnable) {
auto param = GetParam();
auto scale = EFFECT_SCALE.begin();
std::advance(scale, std::rand() % EFFECT_SCALE.size());
auto effect = std::get<0>(scale->first);
auto strength = std::get<1>(scale->first);
switch (param) {
case 0:
case 1:
// Do nothing
break;
}
ndk::ScopedAStatus status = mVibrator->alwaysOnEnable(param, effect, strength);
EXPECT_EQ(EX_NONE, status.getExceptionCode());
}
TEST_P(AlwaysOnTest, alwaysOnDisable) {
auto param = GetParam();
switch (param) {
case 0:
case 1:
// Do nothing
break;
}
ndk::ScopedAStatus status = mVibrator->alwaysOnDisable(param);
EXPECT_EQ(EX_NONE, status.getExceptionCode());
}
INSTANTIATE_TEST_CASE_P(VibratorTests, AlwaysOnTest, Range(0, 1), AlwaysOnTest::PrintParam);
} // namespace vibrator
} // namespace hardware
} // namespace android