1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <glob.h> 19 20 #include <algorithm> 21 22 #include "HardwareBase.h" 23 #include "Vibrator.h" 24 25 #define PROC_SND_PCM "/proc/asound/pcm" 26 #define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback" 27 28 static struct pcm_config haptic_nohost_config = { 29 .channels = 1, 30 .rate = 48000, 31 .period_size = 80, 32 .period_count = 2, 33 .format = PCM_FORMAT_S16_LE, 34 }; 35 36 enum WaveformIndex : uint16_t { 37 /* Physical waveform */ 38 WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, 39 WAVEFORM_RESERVED_INDEX_1 = 1, 40 WAVEFORM_CLICK_INDEX = 2, 41 WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3, 42 WAVEFORM_THUD_INDEX = 4, 43 WAVEFORM_SPIN_INDEX = 5, 44 WAVEFORM_QUICK_RISE_INDEX = 6, 45 WAVEFORM_SLOW_RISE_INDEX = 7, 46 WAVEFORM_QUICK_FALL_INDEX = 8, 47 WAVEFORM_LIGHT_TICK_INDEX = 9, 48 WAVEFORM_LOW_TICK_INDEX = 10, 49 WAVEFORM_RESERVED_MFG_1, 50 WAVEFORM_RESERVED_MFG_2, 51 WAVEFORM_RESERVED_MFG_3, 52 WAVEFORM_MAX_PHYSICAL_INDEX, 53 /* OWT waveform */ 54 WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX, 55 WAVEFORM_PWLE, 56 /* 57 * Refer to <linux/input.h>, the WAVEFORM_MAX_INDEX must not exceed 96. 58 * #define FF_GAIN 0x60 // 96 in decimal 59 * #define FF_MAX_EFFECTS FF_GAIN 60 */ 61 WAVEFORM_MAX_INDEX, 62 }; 63 64 namespace aidl { 65 namespace android { 66 namespace hardware { 67 namespace vibrator { 68 69 class HwApi : public Vibrator::HwApi, private HwApiBase { 70 public: HwApi()71 HwApi() { 72 HwApi::initFF(); 73 open("calibration/f0_stored", &mF0); 74 open("default/f0_offset", &mF0Offset); 75 open("calibration/redc_stored", &mRedc); 76 open("calibration/q_stored", &mQ); 77 open("default/vibe_state", &mVibeState); 78 open("default/num_waves", &mEffectCount); 79 open("default/owt_free_space", &mOwtFreeSpace); 80 open("default/f0_comp_enable", &mF0CompEnable); 81 open("default/redc_comp_enable", &mRedcCompEnable); 82 open("default/delay_before_stop_playback_us", &mMinOnOffInterval); 83 } 84 setF0(std::string value)85 bool setF0(std::string value) override { return set(value, &mF0); } setF0Offset(uint32_t value)86 bool setF0Offset(uint32_t value) override { return set(value, &mF0Offset); } setRedc(std::string value)87 bool setRedc(std::string value) override { return set(value, &mRedc); } setQ(std::string value)88 bool setQ(std::string value) override { return set(value, &mQ); } getEffectCount(uint32_t * value)89 bool getEffectCount(uint32_t *value) override { return get(value, &mEffectCount); } pollVibeState(uint32_t value,int32_t timeoutMs)90 bool pollVibeState(uint32_t value, int32_t timeoutMs) override { 91 return poll(value, &mVibeState, timeoutMs); 92 } hasOwtFreeSpace()93 bool hasOwtFreeSpace() override { return has(mOwtFreeSpace); } getOwtFreeSpace(uint32_t * value)94 bool getOwtFreeSpace(uint32_t *value) override { return get(value, &mOwtFreeSpace); } setF0CompEnable(bool value)95 bool setF0CompEnable(bool value) override { return set(value, &mF0CompEnable); } setRedcCompEnable(bool value)96 bool setRedcCompEnable(bool value) override { return set(value, &mRedcCompEnable); } setMinOnOffInterval(uint32_t value)97 bool setMinOnOffInterval(uint32_t value) override { return set(value, &mMinOnOffInterval); } getContextScale()98 uint32_t getContextScale() override { 99 return utils::getProperty("persist.vendor.vibrator.hal.context.scale", 100); 100 } getContextEnable()101 bool getContextEnable() override { 102 return utils::getProperty("persist.vendor.vibrator.hal.context.enable", false); 103 } getContextSettlingTime()104 uint32_t getContextSettlingTime() override { 105 return utils::getProperty("persist.vendor.vibrator.hal.context.settlingtime", 3000); 106 } getContextCooldownTime()107 uint32_t getContextCooldownTime() override { 108 return utils::getProperty("persist.vendor.vibrator.hal.context.cooldowntime", 1000); 109 } getContextFadeEnable()110 bool getContextFadeEnable() override { 111 return utils::getProperty("persist.vendor.vibrator.hal.context.fade", false); 112 } 113 114 // TODO(b/234338136): Need to add the force feedback HW API test cases initFF()115 bool initFF() override { 116 ATRACE_NAME(__func__); 117 const std::string INPUT_EVENT_NAME = std::getenv("INPUT_EVENT_NAME") ?: ""; 118 if (INPUT_EVENT_NAME.find("cs40l26") == std::string::npos) { 119 ALOGE("Invalid input name: %s", INPUT_EVENT_NAME.c_str()); 120 return false; 121 } 122 123 glob_t g = {}; 124 const std::string INPUT_EVENT_PATH = "/dev/input/event*"; 125 int fd = -1, ret; 126 uint32_t val = 0; 127 char str[256] = {0x00}; 128 // Scan /dev/input/event* to get the correct input device path for FF effects manipulation. 129 // Then constructs the /sys/class/input/event*/../../../ for driver attributes accessing 130 // across different platforms and different kernels. 131 for (uint8_t retry = 1; retry < 11 && !mInputFd.ok(); retry++) { 132 ret = glob(INPUT_EVENT_PATH.c_str(), 0, nullptr, &g); 133 if (ret) { 134 ALOGE("Failed to get input event paths (%d): %s", errno, strerror(errno)); 135 } else { 136 for (size_t i = 0; i < g.gl_pathc; i++) { 137 fd = TEMP_FAILURE_RETRY(::open(g.gl_pathv[i], O_RDWR)); 138 if (fd < 0) { 139 continue; 140 } 141 // Determine the input device path: 142 // 1. Check if EV_FF is flagged in event bits. 143 // 2. Match device name(s) with this CS40L26 HAL instance. 144 if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && (val & (1 << EV_FF)) && 145 ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 && 146 strcmp(str, INPUT_EVENT_NAME.c_str()) == 0) { 147 // Get fd ready for input event ioctl(). 148 mInputFd.reset(fd); // mInputFd.ok() becomes true. 149 ALOGI("Control %s through %s", INPUT_EVENT_NAME.c_str(), g.gl_pathv[i]); 150 151 std::string path = g.gl_pathv[i]; 152 // Get fstream ready for input event write(). 153 saveName(path, &mInputIoStream); 154 mInputIoStream.open( 155 path, std::fstream::out | std::fstream::in | std::fstream::binary); 156 if (!mInputIoStream) { 157 ALOGE("Failed to open %s (%d): %s", path.c_str(), errno, 158 strerror(errno)); 159 } 160 161 // Construct the sysfs device path. 162 path = "/sys/class/input/" + 163 path.substr(path.find("event"), std::string::npos) + "/../../../"; 164 updatePathPrefix(path); 165 break; 166 } 167 close(fd); 168 memset(str, 0x00, sizeof(str)); 169 val = 0; 170 } 171 } 172 173 if (!mInputFd.ok()) { 174 sleep(1); 175 ALOGW("Retry #%d to search in %zu input devices...", retry, g.gl_pathc); 176 } 177 } 178 globfree(&g); 179 180 if (!mInputFd.ok()) { 181 ALOGE("Failed to get an input event with name %s", INPUT_EVENT_NAME.c_str()); 182 return false; 183 } 184 185 return true; 186 } setFFGain(uint16_t value)187 bool setFFGain(uint16_t value) override { 188 ATRACE_NAME(StringPrintf("%s %d%%", __func__, value).c_str()); 189 struct input_event gain = { 190 .type = EV_FF, 191 .code = FF_GAIN, 192 .value = value, 193 }; 194 if (value > 100) { 195 ALOGE("Invalid gain"); 196 return false; 197 } 198 mInputIoStream.write((const char *)&gain, sizeof(gain)); 199 mInputIoStream.flush(); 200 if (mInputIoStream.fail()) { 201 ALOGE("setFFGain fail"); 202 return false; 203 } 204 HWAPI_RECORD(StringPrintf("%d%%", value), &mInputIoStream); 205 return true; 206 } setFFEffect(struct ff_effect * effect,uint16_t timeoutMs)207 bool setFFEffect(struct ff_effect *effect, uint16_t timeoutMs) override { 208 ATRACE_NAME(StringPrintf("%s %dms", __func__, timeoutMs).c_str()); 209 if (effect == nullptr) { 210 ALOGE("Invalid ff_effect"); 211 return false; 212 } 213 if (ioctl(mInputFd, EVIOCSFF, effect) < 0) { 214 ALOGE("setFFEffect fail"); 215 return false; 216 } 217 HWAPI_RECORD(StringPrintf("#%d: %dms", (*effect).id, timeoutMs), &mInputIoStream); 218 return true; 219 } setFFPlay(int8_t index,bool value)220 bool setFFPlay(int8_t index, bool value) override { 221 ATRACE_NAME(StringPrintf("%s index:%d %s", __func__, index, value ? "on" : "off").c_str()); 222 struct input_event play = { 223 .type = EV_FF, 224 .code = static_cast<uint16_t>(index), 225 .value = value, 226 }; 227 mInputIoStream.write((const char *)&play, sizeof(play)); 228 mInputIoStream.flush(); 229 if (mInputIoStream.fail()) { 230 ALOGE("setFFPlay fail"); 231 return false; 232 } 233 HWAPI_RECORD(StringPrintf("#%d: %b", index, value), &mInputIoStream); 234 return true; 235 } getHapticAlsaDevice(int * card,int * device)236 bool getHapticAlsaDevice(int *card, int *device) override { 237 ATRACE_NAME(__func__); 238 std::string line; 239 std::ifstream myfile(PROC_SND_PCM); 240 if (myfile.is_open()) { 241 while (getline(myfile, line)) { 242 if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) { 243 std::stringstream ss(line); 244 std::string currentToken; 245 std::getline(ss, currentToken, ':'); 246 sscanf(currentToken.c_str(), "%d-%d", card, device); 247 saveName(StringPrintf("/dev/snd/pcmC%uD%up", *card, *device), &mPcmStream); 248 return true; 249 } 250 } 251 myfile.close(); 252 } else { 253 ALOGE("Failed to read file: %s", PROC_SND_PCM); 254 } 255 return false; 256 } setHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)257 bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) override { 258 ATRACE_NAME(StringPrintf("%s %s", __func__, enable ? "enable" : "disable").c_str()); 259 int ret = 0; 260 261 if (enable) { 262 *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config); 263 if (!pcm_is_ready(*haptic_pcm)) { 264 ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm)); 265 goto fail; 266 } 267 HWAPI_RECORD(std::string("pcm_open"), &mPcmStream); 268 269 ret = pcm_prepare(*haptic_pcm); 270 if (ret < 0) { 271 ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm)); 272 goto fail; 273 } 274 HWAPI_RECORD(std::string("pcm_prepare"), &mPcmStream); 275 276 ret = pcm_start(*haptic_pcm); 277 if (ret < 0) { 278 ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm)); 279 goto fail; 280 } 281 HWAPI_RECORD(std::string("pcm_start"), &mPcmStream); 282 283 return true; 284 } else { 285 if (*haptic_pcm) { 286 pcm_close(*haptic_pcm); 287 HWAPI_RECORD(std::string("pcm_close"), &mPcmStream); 288 *haptic_pcm = NULL; 289 } 290 return true; 291 } 292 293 fail: 294 pcm_close(*haptic_pcm); 295 HWAPI_RECORD(std::string("pcm_close"), &mPcmStream); 296 *haptic_pcm = NULL; 297 return false; 298 } isPassthroughI2sHapticSupported()299 bool isPassthroughI2sHapticSupported() override { 300 return utils::getProperty("ro.vendor.vibrator.hal.passthrough_i2s_supported", false); 301 } uploadOwtEffect(const uint8_t * owtData,const uint32_t numBytes,struct ff_effect * effect,uint32_t * outEffectIndex,int * status)302 bool uploadOwtEffect(const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect, 303 uint32_t *outEffectIndex, int *status) override { 304 ATRACE_NAME(__func__); 305 if (owtData == nullptr || effect == nullptr || outEffectIndex == nullptr) { 306 ALOGE("Invalid argument owtData, ff_effect or outEffectIndex"); 307 *status = EX_NULL_POINTER; 308 return false; 309 } 310 if (status == nullptr) { 311 ALOGE("Invalid argument status"); 312 return false; 313 } 314 315 (*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t); 316 memcpy((*effect).u.periodic.custom_data, owtData, numBytes); 317 318 if ((*effect).id != -1) { 319 ALOGE("(*effect).id != -1"); 320 } 321 322 /* Create a new OWT waveform to update the PWLE or composite effect. */ 323 (*effect).id = -1; 324 if (ioctl(mInputFd, EVIOCSFF, effect) < 0) { 325 ALOGE("Failed to upload effect %d (%d): %s", *outEffectIndex, errno, strerror(errno)); 326 *status = EX_ILLEGAL_STATE; 327 return false; 328 } 329 330 if ((*effect).id >= FF_MAX_EFFECTS || (*effect).id < 0) { 331 ALOGE("Invalid waveform index after upload OWT effect: %d", (*effect).id); 332 *status = EX_ILLEGAL_ARGUMENT; 333 return false; 334 } 335 *outEffectIndex = (*effect).id; 336 *status = 0; 337 HWAPI_RECORD(StringPrintf("#%d: %dB", *outEffectIndex, numBytes), &mInputIoStream); 338 return true; 339 } eraseOwtEffect(int8_t effectIndex,std::vector<ff_effect> * effect)340 bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) override { 341 ATRACE_NAME(__func__); 342 uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0; 343 344 if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { 345 ALOGE("Invalid waveform index for OWT erase: %d", effectIndex); 346 return false; 347 } 348 if (effect == nullptr || (*effect).empty()) { 349 ALOGE("Invalid argument effect"); 350 return false; 351 } 352 353 if (effectIndex < WAVEFORM_MAX_INDEX) { 354 /* Normal situation. Only erase the effect which we just played. */ 355 if (ioctl(mInputFd, EVIOCRMFF, effectIndex) < 0) { 356 ALOGE("Failed to erase effect %d (%d): %s", effectIndex, errno, strerror(errno)); 357 } 358 for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { 359 if ((*effect)[i].id == effectIndex) { 360 (*effect)[i].id = -1; 361 break; 362 } 363 } 364 HWAPI_RECORD(StringPrintf("#%d", effectIndex), &mInputIoStream); 365 } else { 366 /* Flush all non-prestored effects of ff-core and driver. */ 367 getEffectCount(&effectCountBefore); 368 for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) { 369 if (ioctl(mInputFd, EVIOCRMFF, i) >= 0) { 370 successFlush++; 371 HWAPI_RECORD(StringPrintf("#%d", i), &mInputIoStream); 372 } 373 } 374 getEffectCount(&effectCountAfter); 375 ALOGW("Flushed effects: ff: %d; driver: %d -> %d; success: %d", effectIndex, 376 effectCountBefore, effectCountAfter, successFlush); 377 /* Reset all OWT effect index of HAL. */ 378 for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { 379 (*effect)[i].id = -1; 380 } 381 } 382 return true; 383 } isDbcSupported()384 bool isDbcSupported() override { 385 ATRACE_NAME(__func__); 386 return utils::getProperty("ro.vendor.vibrator.hal.dbc.enable", false); 387 } 388 enableDbc()389 bool enableDbc() override { 390 ATRACE_NAME(__func__); 391 if (isDbcSupported()) { 392 open("dbc/dbc_env_rel_coef", &mDbcEnvRelCoef); 393 open("dbc/dbc_rise_headroom", &mDbcRiseHeadroom); 394 open("dbc/dbc_fall_headroom", &mDbcFallHeadroom); 395 open("dbc/dbc_tx_lvl_thresh_fs", &mDbcTxLvlThreshFs); 396 open("dbc/dbc_tx_lvl_hold_off_ms", &mDbcTxLvlHoldOffMs); 397 open("default/pm_active_timeout_ms", &mPmActiveTimeoutMs); 398 open("dbc/dbc_enable", &mDbcEnable); 399 400 // Set values from config. Default if not found. 401 set(utils::getProperty("ro.vendor.vibrator.hal.dbc.envrelcoef", kDbcDefaultEnvRelCoef), 402 &mDbcEnvRelCoef); 403 set(utils::getProperty("ro.vendor.vibrator.hal.dbc.riseheadroom", 404 kDbcDefaultRiseHeadroom), 405 &mDbcRiseHeadroom); 406 set(utils::getProperty("ro.vendor.vibrator.hal.dbc.fallheadroom", 407 kDbcDefaultFallHeadroom), 408 &mDbcFallHeadroom); 409 set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlthreshfs", 410 kDbcDefaultTxLvlThreshFs), 411 &mDbcTxLvlThreshFs); 412 set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlholdoffms", 413 kDbcDefaultTxLvlHoldOffMs), 414 &mDbcTxLvlHoldOffMs); 415 set(utils::getProperty("ro.vendor.vibrator.hal.pm.activetimeout", 416 kDefaultPmActiveTimeoutMs), 417 &mPmActiveTimeoutMs); 418 set(kDbcEnable, &mDbcEnable); 419 return true; 420 } 421 return false; 422 } 423 debug(int fd)424 void debug(int fd) override { HwApiBase::debug(fd); } 425 426 private: 427 static constexpr uint32_t kDbcDefaultEnvRelCoef = 8353728; 428 static constexpr uint32_t kDbcDefaultRiseHeadroom = 1909602; 429 static constexpr uint32_t kDbcDefaultFallHeadroom = 1909602; 430 static constexpr uint32_t kDbcDefaultTxLvlThreshFs = 2516583; 431 static constexpr uint32_t kDbcDefaultTxLvlHoldOffMs = 0; 432 static constexpr uint32_t kDefaultPmActiveTimeoutMs = 5; 433 static constexpr uint32_t kDbcEnable = 1; 434 435 std::ofstream mF0; 436 std::ofstream mF0Offset; 437 std::ofstream mRedc; 438 std::ofstream mQ; 439 std::ifstream mEffectCount; 440 std::ifstream mVibeState; 441 std::ifstream mOwtFreeSpace; 442 std::ofstream mF0CompEnable; 443 std::ofstream mRedcCompEnable; 444 std::ofstream mMinOnOffInterval; 445 std::ofstream mInputIoStream; 446 std::ofstream mPcmStream; 447 ::android::base::unique_fd mInputFd; 448 449 // DBC Parameters 450 std::ofstream mDbcEnvRelCoef; 451 std::ofstream mDbcRiseHeadroom; 452 std::ofstream mDbcFallHeadroom; 453 std::ofstream mDbcTxLvlThreshFs; 454 std::ofstream mDbcTxLvlHoldOffMs; 455 std::ofstream mDbcEnable; 456 std::ofstream mPmActiveTimeoutMs; 457 }; 458 459 class HwCal : public Vibrator::HwCal, private HwCalBase { 460 private: 461 static constexpr char VERSION[] = "version"; 462 static constexpr char F0_CONFIG[] = "f0_measured"; 463 static constexpr char REDC_CONFIG[] = "redc_measured"; 464 static constexpr char Q_CONFIG[] = "q_measured"; 465 static constexpr char TICK_VOLTAGES_CONFIG[] = "v_tick"; 466 static constexpr char CLICK_VOLTAGES_CONFIG[] = "v_click"; 467 static constexpr char LONG_VOLTAGES_CONFIG[] = "v_long"; 468 469 static constexpr uint32_t VERSION_DEFAULT = 2; 470 static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0; 471 static constexpr float DEFAULT_DEVICE_MASS = 0.21; 472 static constexpr float DEFAULT_LOC_COEFF = 2.5; 473 static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {5, 95}; 474 static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {5, 95}; 475 static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {5, 95}; 476 477 public: HwCal()478 HwCal() {} 479 getVersion(uint32_t * value)480 bool getVersion(uint32_t *value) override { 481 if (getPersist(VERSION, value)) { 482 return true; 483 } 484 *value = VERSION_DEFAULT; 485 return true; 486 } getLongFrequencyShift(int32_t * value)487 bool getLongFrequencyShift(int32_t *value) override { 488 return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT); 489 } getDeviceMass(float * value)490 bool getDeviceMass(float *value) override { 491 return getProperty("device.mass", value, DEFAULT_DEVICE_MASS); 492 } getLocCoeff(float * value)493 bool getLocCoeff(float *value) override { 494 return getProperty("loc.coeff", value, DEFAULT_LOC_COEFF); 495 } getF0(std::string * value)496 bool getF0(std::string *value) override { return getPersist(F0_CONFIG, value); } getRedc(std::string * value)497 bool getRedc(std::string *value) override { return getPersist(REDC_CONFIG, value); } getQ(std::string * value)498 bool getQ(std::string *value) override { return getPersist(Q_CONFIG, value); } getTickVolLevels(std::array<uint32_t,2> * value)499 bool getTickVolLevels(std::array<uint32_t, 2> *value) override { 500 if (getPersist(TICK_VOLTAGES_CONFIG, value)) { 501 return true; 502 } 503 return getProperty(TICK_VOLTAGES_CONFIG, value, V_TICK_DEFAULT); 504 } getClickVolLevels(std::array<uint32_t,2> * value)505 bool getClickVolLevels(std::array<uint32_t, 2> *value) override { 506 if (getPersist(CLICK_VOLTAGES_CONFIG, value)) { 507 return true; 508 } 509 return getProperty(CLICK_VOLTAGES_CONFIG, value, V_CLICK_DEFAULT); 510 } getLongVolLevels(std::array<uint32_t,2> * value)511 bool getLongVolLevels(std::array<uint32_t, 2> *value) override { 512 if (getPersist(LONG_VOLTAGES_CONFIG, value)) { 513 return true; 514 } 515 return getProperty(LONG_VOLTAGES_CONFIG, value, V_LONG_DEFAULT); 516 } isChirpEnabled()517 bool isChirpEnabled() override { 518 return utils::getProperty("persist.vendor.vibrator.hal.chirp.enabled", false); 519 } getSupportedPrimitives(uint32_t * value)520 bool getSupportedPrimitives(uint32_t *value) override { 521 return getProperty("supported_primitives", value, (uint32_t)0); 522 } isF0CompEnabled()523 bool isF0CompEnabled() override { 524 bool value; 525 getProperty("f0.comp.enabled", &value, true); 526 return value; 527 } isRedcCompEnabled()528 bool isRedcCompEnabled() override { 529 bool value; 530 getProperty("redc.comp.enabled", &value, false); 531 return value; 532 } debug(int fd)533 void debug(int fd) override { HwCalBase::debug(fd); } 534 }; 535 536 } // namespace vibrator 537 } // namespace hardware 538 } // namespace android 539 } // namespace aidl 540