diff --git a/device-felix.mk b/device-felix.mk index 69e4375..ce2df54 100644 --- a/device-felix.mk +++ b/device-felix.mk @@ -41,8 +41,8 @@ $(call soong_config_set,fp_hal_feature,pixel_product, product_a) include device/google/felix/vibrator/cs40l26/device.mk include device/google/gs-common/bcmbt/bluetooth.mk include device/google/gs-common/display/dump_second_display.mk -include device/google/gs-common/touch/gti/gti.mk -include device/google/gs-common/touch/stm/stm6.mk +include device/google/gs-common/touch/gti/predump_gti_dual.mk +include device/google/gs-common/touch/stm/predump_stm6.mk ifeq ($(filter factory_felix, $(TARGET_PRODUCT)),) include device/google/felix/uwb/uwb_calibration.mk endif diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index 0fe4880..8543bf0 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,30 @@ static constexpr uint8_t PWLE_CHIRP_BIT = 0x8; // Dynamic/static frequency and static constexpr uint8_t PWLE_BRAKE_BIT = 0x4; static constexpr uint8_t PWLE_AMP_REG_BIT = 0x2; +static constexpr uint8_t PWLE_WT_TYPE = 12; +static constexpr uint8_t PWLE_HEADER_WORD_COUNT = 3; +static constexpr uint8_t PWLE_HEADER_FTR_SHIFT = 8; +static constexpr uint8_t PWLE_SVC_METADATA_WORD_COUNT = 3; +static constexpr uint32_t PWLE_SVC_METADATA_TERMINATOR = 0xFFFFFF; +static constexpr uint8_t PWLE_SEGMENT_WORD_COUNT = 2; +static constexpr uint8_t PWLE_HEADER_WCOUNT_WORD_OFFSET = 2; +static constexpr uint8_t PWLE_WORD_SIZE = sizeof(uint32_t); + +static constexpr uint8_t PWLE_SVC_NO_BRAKING = -1; +static constexpr uint8_t PWLE_SVC_CAT_BRAKING = 0; +static constexpr uint8_t PWLE_SVC_OPEN_BRAKING = 1; +static constexpr uint8_t PWLE_SVC_CLOSED_BRAKING = 2; +static constexpr uint8_t PWLE_SVC_MIXED_BRAKING = 3; + +static constexpr uint32_t PWLE_SVC_MAX_BRAKING_TIME_MS = 1000; + +static constexpr uint8_t PWLE_FTR_BUZZ_BIT = 0x80; +static constexpr uint8_t PWLE_FTR_CLICK_BIT = 0x00; +static constexpr uint8_t PWLE_FTR_DYNAMIC_F0_BIT = 0x10; +static constexpr uint8_t PWLE_FTR_SVC_METADATA_BIT = 0x04; +static constexpr uint8_t PWLE_FTR_DVL_BIT = 0x02; +static constexpr uint8_t PWLE_FTR_LF0T_BIT = 0x01; + static constexpr float PWLE_LEVEL_MIN = 0.0; static constexpr float PWLE_LEVEL_MAX = 1.0; static constexpr float CS40L26_PWLE_LEVEL_MIN = -1.0; @@ -245,10 +270,18 @@ class DspMemChunk { write(8, 0); /* nsections placeholder */ write(8, 0); /* repeat */ } else if (waveformType == WAVEFORM_PWLE) { + write(16, (PWLE_FTR_BUZZ_BIT | PWLE_FTR_DVL_BIT) + << PWLE_HEADER_FTR_SHIFT); /* Feature flag */ + write(8, PWLE_WT_TYPE); /* type12 */ + write(24, PWLE_HEADER_WORD_COUNT); /* Header word count */ + write(24, 0); /* Body word count placeholder */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) write(24, 0); /* Waveform length placeholder */ write(8, 0); /* Repeat */ write(12, 0); /* Wait time between repeats */ write(8, 0); /* nsections placeholder */ +#endif } else { ALOGE("%s: Invalid type: %u", __func__, waveformType); } @@ -336,6 +369,9 @@ class DspMemChunk { ALOGE("%s: Invalid argument: %u", __func__, totalDuration); return -EINVAL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE; +#endif 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. */ @@ -364,6 +400,9 @@ class DspMemChunk { ALOGE("%s: Invalid argument: %d", __func__, segmentIdx); return -EINVAL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE; +#endif *(f + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */ *(f + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */ } else { @@ -373,6 +412,34 @@ class DspMemChunk { return 0; } + + int updateWCount(int segmentCount) { + uint8_t *f = front(); + + if (segmentCount > COMPOSE_SIZE_MAX + 1 /*1st effect may have a delay*/) { + ALOGE("%s: Invalid argument: %d", __func__, segmentCount); + return -EINVAL; + } + if (f == nullptr) { + ALOGE("%s: head does not exist!", __func__); + return -ENOMEM; + } + if (waveformType != WAVEFORM_PWLE) { + ALOGE("%s: Invalid type: %d", __func__, waveformType); + return -EDOM; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE; +#endif + uint32_t dataSize = segmentCount * PWLE_SEGMENT_WORD_COUNT + PWLE_HEADER_WORD_COUNT; + *(f + 0) = (dataSize >> 24) & 0xFF; + *(f + 1) = (dataSize >> 16) & 0xFF; + *(f + 2) = (dataSize >> 8) & 0xFF; + *(f + 3) = dataSize & 0xFF; + + return 0; + } }; Vibrator::Vibrator(std::unique_ptr hwApiDefault, std::unique_ptr hwCalDefault, @@ -1370,6 +1437,13 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector &compo return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + /* Update word count */ + if (ch.updateWCount(segmentIdx) < 0) { + ALOGE("%s: Failed to update the waveform word count", __func__); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + /* Update waveform length */ if (ch.updateWLength(totalDuration) < 0) { ALOGE("%s: Failed to update the waveform length length", __func__); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);