otter: vibrator: Update for 15

Update from vendor/qcom/opensource/vibrator
at commit 8f873decb09e5b4c2edf3ab1e1bad14764d943db

Change-Id: I12e0982fc051834628b00da14dde7a5c1c687e53
diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp
index 06d26e0..abecdc9 100644
--- a/vibrator/Vibrator.cpp
+++ b/vibrator/Vibrator.cpp
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -28,7 +27,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Changes from Qualcomm Innovation Center are provided under the following license:
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
@@ -77,6 +76,7 @@
 #define MSM_CPU_TARO            457
 #define MSM_CPU_TARO_LTE        552
 #define MSM_CPU_KALAMA          519
+#define MSM_CPU_PINEAPPLE       557
 
 #define test_bit(bit, array)    ((array)[(bit)/8] & (1<<((bit)%8)))
 
@@ -141,7 +141,8 @@
                 && strcmp(name, "aw8624_haptic")
                 && strcmp(name, "aw8695_haptic")
                 && strcmp(name, "aw8697_haptic")
-                && strcmp(name, "awinic_haptic")) {
+                && strcmp(name, "awinic_haptic")
+                && strcmp(name, "drv2624:haptics")) {
             ALOGD("not a supported haptics device\n");
             close(fd);
             continue;
@@ -179,6 +180,7 @@
             case MSM_CPU_CAPE:
             case APQ_CPU_CAPE:
             case MSM_CPU_KALAMA:
+            case MSM_CPU_PINEAPPLE:
                 mSupportExternalControl = true;
                 break;
             default:
@@ -221,10 +223,12 @@
     const struct effect_stream *stream;
 #endif
 
+    mtx.lock();
     /* For QMAA compliance, return OK even if vibrator device doesn't exist */
     if (mVibraFd == INVALID_VALUE) {
         if (playLengthMs != NULL)
             *playLengthMs = 0;
+        mtx.unlock();
         return 0;
     }
 
@@ -298,10 +302,12 @@
         }
         mCurrAppId = INVALID_VALUE;
     }
+    mtx.unlock();
     return 0;
 
 errout:
     mCurrAppId = INVALID_VALUE;
+    mtx.unlock();
     return ret;
 }
 
@@ -505,6 +511,8 @@
         close(pipefd[1]);
 }
 
+static int getPrimitiveDurationFromSysfs(uint32_t primitive_id, int32_t* durationMs);
+
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     *_aidl_return = IVibrator::CAP_ON_CALLBACK;
 
@@ -516,10 +524,12 @@
     if (ff.mSupportGain)
         *_aidl_return |= IVibrator::CAP_AMPLITUDE_CONTROL;
     if (ff.mSupportEffects) {
-       *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK;
-        if (access("/sys/class/qcom-haptics/primitive_duration", F_OK) == 0) {
+        *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK;
+        int32_t primitiveDuration = 0;
+        uint32_t primitiveId = static_cast<uint32_t>(CompositePrimitive::CLICK);
+        getPrimitiveDurationFromSysfs(primitiveId, &primitiveDuration);
+        if (primitiveDuration != 0)
             *_aidl_return |= IVibrator::CAP_COMPOSE_EFFECTS;
-        }
     }
     if (ff.mSupportExternalControl)
         *_aidl_return |= IVibrator::CAP_EXTERNAL_CONTROL;
@@ -821,8 +831,32 @@
                 ALOGE("Failed to read stop status from pipe(playLengthMs), status = %d", status);
                 break;
             }
-            if (status == STOP_COMPOSE)
+            if (status == STOP_COMPOSE) {
+
+                /*
+                 * There is a corner case that the off() command could be executed in
+                 * main thread before the primitive play is triggered in the child thread,
+                 * such as, when playing a very short primitive effect while the system is
+                 * pretty busy (one example is enabling all kernel console log after executed
+                 * "echo Y > /sys/module/printk/parameters/ignore_loglevel"), the child thread
+                 * may not be able to schedule out for running before the main thread times out
+                 * on the primitive duration and sent the off() command, there won't be any
+                 * off() command coming again to stop the primitive effect after it's triggered.
+                 *
+                 * However, the primitive could be played out and stopped automatically but the
+                 * haptics driver does expect an explicit off() command to restore HW/SW logic
+                 * after that, so call it here. It would result a redundant off() command in
+                 * normal case but it won't do any harm because it would be ignored and not sent
+                 * to haptics driver because of an invalid mCurrAppId. It would also result in the
+                 * primitive effect to stop immediately right after it's triggered in such
+                 * corner case. But considering the main thread has stopped it before off() is
+                 * called here, take this as a limitation and it is expected not playing the
+                 * vibration out.
+                 */
+
+                vibrator->ff.off();
                 break;
+            }
         }
     }
 
@@ -877,15 +911,17 @@
             ALOGE("wait for last composePlayThread done timeout");
             return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
         }
+    }
 
-        /* Read the pipe again to remove any stale data before triggering a new play */
-        nfd = epoll_wait(epollfd, &events, 1, 0);
-        if (nfd == -1 && (errno != EINTR)) {
-            ALOGE("Failed to wait sleep playLengthMs, error=%d", errno);
-            return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
-        }
-        if (nfd > 0)
-            read(pipefd[0], &status, sizeof(int));
+    /* Read the pipe again to remove any stale data before triggering a new play */
+    nfd = epoll_wait(epollfd, &events, 1, 0);
+    if (nfd == -1 && (errno != EINTR)) {
+        ALOGE("Failed to wait sleep playLengthMs, error=%d", errno);
+        return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+    }
+    if (nfd > 0) {
+        ALOGD("A stale event is cached in the pipe, remove it");
+        read(pipefd[0], &status, sizeof(int));
     }
 
     inComposition = true;