• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (((*effect).replay.length != timeoutMs) || (ioctl(mInputFd, EVIOCSFF, effect) < 0)) {
214             ALOGE("setFFEffect fail");
215             return false;
216         }
217         HWAPI_RECORD(StringPrintf("#%d: %dms", (*effect).id, (*effect).replay.length),
218                      &mInputIoStream);
219         return true;
220     }
setFFPlay(int8_t index,bool value)221     bool setFFPlay(int8_t index, bool value) override {
222         ATRACE_NAME(StringPrintf("%s index:%d %s", __func__, index, value ? "on" : "off").c_str());
223         struct input_event play = {
224                 .type = EV_FF,
225                 .code = static_cast<uint16_t>(index),
226                 .value = value,
227         };
228         mInputIoStream.write((const char *)&play, sizeof(play));
229         mInputIoStream.flush();
230         if (mInputIoStream.fail()) {
231             ALOGE("setFFPlay fail");
232             return false;
233         }
234         HWAPI_RECORD(StringPrintf("#%d: %b", index, value), &mInputIoStream);
235         return true;
236     }
getHapticAlsaDevice(int * card,int * device)237     bool getHapticAlsaDevice(int *card, int *device) override {
238         ATRACE_NAME(__func__);
239         std::string line;
240         std::ifstream myfile(PROC_SND_PCM);
241         if (myfile.is_open()) {
242             while (getline(myfile, line)) {
243                 if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) {
244                     std::stringstream ss(line);
245                     std::string currentToken;
246                     std::getline(ss, currentToken, ':');
247                     sscanf(currentToken.c_str(), "%d-%d", card, device);
248                     saveName(StringPrintf("/dev/snd/pcmC%uD%up", *card, *device), &mPcmStream);
249                     return true;
250                 }
251             }
252             myfile.close();
253         } else {
254             ALOGE("Failed to read file: %s", PROC_SND_PCM);
255         }
256         return false;
257     }
setHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)258     bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) override {
259         ATRACE_NAME(StringPrintf("%s %s", __func__, enable ? "enable" : "disable").c_str());
260         int ret = 0;
261 
262         if (enable) {
263             *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config);
264             if (!pcm_is_ready(*haptic_pcm)) {
265                 ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm));
266                 goto fail;
267             }
268             HWAPI_RECORD(std::string("pcm_open"), &mPcmStream);
269 
270             ret = pcm_prepare(*haptic_pcm);
271             if (ret < 0) {
272                 ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm));
273                 goto fail;
274             }
275             HWAPI_RECORD(std::string("pcm_prepare"), &mPcmStream);
276 
277             ret = pcm_start(*haptic_pcm);
278             if (ret < 0) {
279                 ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm));
280                 goto fail;
281             }
282             HWAPI_RECORD(std::string("pcm_start"), &mPcmStream);
283 
284             return true;
285         } else {
286             if (*haptic_pcm) {
287                 pcm_close(*haptic_pcm);
288                 HWAPI_RECORD(std::string("pcm_close"), &mPcmStream);
289                 *haptic_pcm = NULL;
290             }
291             return true;
292         }
293 
294     fail:
295         pcm_close(*haptic_pcm);
296         HWAPI_RECORD(std::string("pcm_close"), &mPcmStream);
297         *haptic_pcm = NULL;
298         return false;
299     }
uploadOwtEffect(const uint8_t * owtData,const uint32_t numBytes,struct ff_effect * effect,uint32_t * outEffectIndex,int * status)300     bool uploadOwtEffect(const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect,
301                          uint32_t *outEffectIndex, int *status) override {
302         ATRACE_NAME(__func__);
303         if (owtData == nullptr || effect == nullptr || outEffectIndex == nullptr) {
304             ALOGE("Invalid argument owtData, ff_effect or outEffectIndex");
305             *status = EX_NULL_POINTER;
306             return false;
307         }
308         if (status == nullptr) {
309             ALOGE("Invalid argument status");
310             return false;
311         }
312 
313         (*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t);
314         memcpy((*effect).u.periodic.custom_data, owtData, numBytes);
315 
316         if ((*effect).id != -1) {
317             ALOGE("(*effect).id != -1");
318         }
319 
320         /* Create a new OWT waveform to update the PWLE or composite effect. */
321         (*effect).id = -1;
322         if (ioctl(mInputFd, EVIOCSFF, effect) < 0) {
323             ALOGE("Failed to upload effect %d (%d): %s", *outEffectIndex, errno, strerror(errno));
324             *status = EX_ILLEGAL_STATE;
325             return false;
326         }
327 
328         if ((*effect).id >= FF_MAX_EFFECTS || (*effect).id < 0) {
329             ALOGE("Invalid waveform index after upload OWT effect: %d", (*effect).id);
330             *status = EX_ILLEGAL_ARGUMENT;
331             return false;
332         }
333         *outEffectIndex = (*effect).id;
334         *status = 0;
335         HWAPI_RECORD(StringPrintf("#%d: %dB", *outEffectIndex, numBytes), &mInputIoStream);
336         return true;
337     }
eraseOwtEffect(int8_t effectIndex,std::vector<ff_effect> * effect)338     bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) override {
339         ATRACE_NAME(__func__);
340         uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0;
341 
342         if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) {
343             ALOGE("Invalid waveform index for OWT erase: %d", effectIndex);
344             return false;
345         }
346         if (effect == nullptr || (*effect).empty()) {
347             ALOGE("Invalid argument effect");
348             return false;
349         }
350 
351         if (effectIndex < WAVEFORM_MAX_INDEX) {
352             /* Normal situation. Only erase the effect which we just played. */
353             if (ioctl(mInputFd, EVIOCRMFF, effectIndex) < 0) {
354                 ALOGE("Failed to erase effect %d (%d): %s", effectIndex, errno, strerror(errno));
355             }
356             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) {
357                 if ((*effect)[i].id == effectIndex) {
358                     (*effect)[i].id = -1;
359                     break;
360                 }
361             }
362             HWAPI_RECORD(StringPrintf("#%d", effectIndex), &mInputIoStream);
363         } else {
364             /* Flush all non-prestored effects of ff-core and driver. */
365             getEffectCount(&effectCountBefore);
366             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) {
367                 if (ioctl(mInputFd, EVIOCRMFF, i) >= 0) {
368                     successFlush++;
369                     HWAPI_RECORD(StringPrintf("#%d", i), &mInputIoStream);
370                 }
371             }
372             getEffectCount(&effectCountAfter);
373             ALOGW("Flushed effects: ff: %d; driver: %d -> %d; success: %d", effectIndex,
374                   effectCountBefore, effectCountAfter, successFlush);
375             /* Reset all OWT effect index of HAL. */
376             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) {
377                 (*effect)[i].id = -1;
378             }
379         }
380         return true;
381     }
isDbcSupported()382     bool isDbcSupported() override {
383         ATRACE_NAME(__func__);
384         return utils::getProperty("ro.vendor.vibrator.hal.dbc.enable", false);
385     }
386 
enableDbc()387     bool enableDbc() override {
388         ATRACE_NAME(__func__);
389         if (isDbcSupported()) {
390             open("dbc/dbc_env_rel_coef", &mDbcEnvRelCoef);
391             open("dbc/dbc_rise_headroom", &mDbcRiseHeadroom);
392             open("dbc/dbc_fall_headroom", &mDbcFallHeadroom);
393             open("dbc/dbc_tx_lvl_thresh_fs", &mDbcTxLvlThreshFs);
394             open("dbc/dbc_tx_lvl_hold_off_ms", &mDbcTxLvlHoldOffMs);
395             open("default/pm_active_timeout_ms", &mPmActiveTimeoutMs);
396             open("dbc/dbc_enable", &mDbcEnable);
397 
398             // Set values from config. Default if not found.
399             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.envrelcoef", kDbcDefaultEnvRelCoef),
400                 &mDbcEnvRelCoef);
401             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.riseheadroom",
402                                    kDbcDefaultRiseHeadroom),
403                 &mDbcRiseHeadroom);
404             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.fallheadroom",
405                                    kDbcDefaultFallHeadroom),
406                 &mDbcFallHeadroom);
407             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlthreshfs",
408                                    kDbcDefaultTxLvlThreshFs),
409                 &mDbcTxLvlThreshFs);
410             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlholdoffms",
411                                    kDbcDefaultTxLvlHoldOffMs),
412                 &mDbcTxLvlHoldOffMs);
413             set(utils::getProperty("ro.vendor.vibrator.hal.pm.activetimeout",
414                                    kDefaultPmActiveTimeoutMs),
415                 &mPmActiveTimeoutMs);
416             set(kDbcEnable, &mDbcEnable);
417             return true;
418         }
419         return false;
420     }
421 
debug(int fd)422     void debug(int fd) override { HwApiBase::debug(fd); }
423 
424   private:
425     static constexpr uint32_t kDbcDefaultEnvRelCoef = 8353728;
426     static constexpr uint32_t kDbcDefaultRiseHeadroom = 1909602;
427     static constexpr uint32_t kDbcDefaultFallHeadroom = 1909602;
428     static constexpr uint32_t kDbcDefaultTxLvlThreshFs = 2516583;
429     static constexpr uint32_t kDbcDefaultTxLvlHoldOffMs = 0;
430     static constexpr uint32_t kDefaultPmActiveTimeoutMs = 5;
431     static constexpr uint32_t kDbcEnable = 1;
432 
433     std::ofstream mF0;
434     std::ofstream mF0Offset;
435     std::ofstream mRedc;
436     std::ofstream mQ;
437     std::ifstream mEffectCount;
438     std::ifstream mVibeState;
439     std::ifstream mOwtFreeSpace;
440     std::ofstream mF0CompEnable;
441     std::ofstream mRedcCompEnable;
442     std::ofstream mMinOnOffInterval;
443     std::ofstream mInputIoStream;
444     std::ofstream mPcmStream;
445     ::android::base::unique_fd mInputFd;
446 
447     // DBC Parameters
448     std::ofstream mDbcEnvRelCoef;
449     std::ofstream mDbcRiseHeadroom;
450     std::ofstream mDbcFallHeadroom;
451     std::ofstream mDbcTxLvlThreshFs;
452     std::ofstream mDbcTxLvlHoldOffMs;
453     std::ofstream mDbcEnable;
454     std::ofstream mPmActiveTimeoutMs;
455 };
456 
457 class HwCal : public Vibrator::HwCal, private HwCalBase {
458   private:
459     static constexpr char VERSION[] = "version";
460     static constexpr char F0_CONFIG[] = "f0_measured";
461     static constexpr char REDC_CONFIG[] = "redc_measured";
462     static constexpr char Q_CONFIG[] = "q_measured";
463     static constexpr char TICK_VOLTAGES_CONFIG[] = "v_tick";
464     static constexpr char CLICK_VOLTAGES_CONFIG[] = "v_click";
465     static constexpr char LONG_VOLTAGES_CONFIG[] = "v_long";
466 
467     static constexpr uint32_t VERSION_DEFAULT = 2;
468     static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0;
469     static constexpr float DEFAULT_DEVICE_MASS = 0.21;
470     static constexpr float DEFAULT_LOC_COEFF = 2.5;
471     static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {1, 100};
472     static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {1, 100};
473     static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {1, 100};
474 
475   public:
HwCal()476     HwCal() {}
477 
getVersion(uint32_t * value)478     bool getVersion(uint32_t *value) override {
479         if (getPersist(VERSION, value)) {
480             return true;
481         }
482         *value = VERSION_DEFAULT;
483         return true;
484     }
getLongFrequencyShift(int32_t * value)485     bool getLongFrequencyShift(int32_t *value) override {
486         return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT);
487     }
getDeviceMass(float * value)488     bool getDeviceMass(float *value) override {
489         return getProperty("device.mass", value, DEFAULT_DEVICE_MASS);
490     }
getLocCoeff(float * value)491     bool getLocCoeff(float *value) override {
492         return getProperty("loc.coeff", value, DEFAULT_LOC_COEFF);
493     }
getF0(std::string * value)494     bool getF0(std::string *value) override { return getPersist(F0_CONFIG, value); }
getRedc(std::string * value)495     bool getRedc(std::string *value) override { return getPersist(REDC_CONFIG, value); }
getQ(std::string * value)496     bool getQ(std::string *value) override { return getPersist(Q_CONFIG, value); }
getTickVolLevels(std::array<uint32_t,2> * value)497     bool getTickVolLevels(std::array<uint32_t, 2> *value) override {
498         if (getPersist(TICK_VOLTAGES_CONFIG, value)) {
499             return true;
500         }
501         *value = V_TICK_DEFAULT;
502         return true;
503     }
getClickVolLevels(std::array<uint32_t,2> * value)504     bool getClickVolLevels(std::array<uint32_t, 2> *value) override {
505         if (getPersist(CLICK_VOLTAGES_CONFIG, value)) {
506             return true;
507         }
508         *value = V_CLICK_DEFAULT;
509         return true;
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         *value = V_LONG_DEFAULT;
516         return true;
517     }
isChirpEnabled()518     bool isChirpEnabled() override {
519         bool value;
520         getProperty("chirp.enabled", &value, false);
521         return value;
522     }
getSupportedPrimitives(uint32_t * value)523     bool getSupportedPrimitives(uint32_t *value) override {
524         return getProperty("supported_primitives", value, (uint32_t)0);
525     }
isF0CompEnabled()526     bool isF0CompEnabled() override {
527         bool value;
528         getProperty("f0.comp.enabled", &value, true);
529         return value;
530     }
isRedcCompEnabled()531     bool isRedcCompEnabled() override {
532         bool value;
533         getProperty("redc.comp.enabled", &value, false);
534         return value;
535     }
debug(int fd)536     void debug(int fd) override { HwCalBase::debug(fd); }
537 };
538 
539 }  // namespace vibrator
540 }  // namespace hardware
541 }  // namespace android
542 }  // namespace aidl
543