From 4ef96a6f9a7962ada173c9a950c404bc2a0a7513 Mon Sep 17 00:00:00 2001 From: LameMonster82 Date: Thu, 4 Jun 2020 13:31:12 +0200 Subject: [PATCH] add support for TSPDRV vibration * Needed for the LG V30, G7, V35, V40 * Use TW_HAPTICS_TSPDRV in your BoardConfig.mk to enable it. Change-Id: I0970ed5c046e851f7e6f562283523c7214c8d2b5 (cherry picked from commit 314cbd5698d1750a31c9cf4284d3ce8dfadce157) --- minuitwrp/Android.mk | 5 ++ minuitwrp/events.cpp | 2 + minuitwrp/tspdrv.cpp | 193 +++++++++++++++++++++++++++++++++++++++++++ minuitwrp/tspdrv.h | 100 ++++++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 minuitwrp/tspdrv.cpp create mode 100644 minuitwrp/tspdrv.h diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk index 2b5650da..ac09e494 100644 --- a/minuitwrp/Android.mk +++ b/minuitwrp/Android.mk @@ -190,6 +190,11 @@ ifneq ($(TW_WHITELIST_INPUT),) LOCAL_CFLAGS += -DWHITELIST_INPUT=$(TW_WHITELIST_INPUT) endif +ifeq ($(TW_HAPTICS_TSPDRV), true) + LOCAL_SRC_FILES += tspdrv.cpp + LOCAL_CFLAGS += -DTW_HAPTICS_TSPDRV +endif + ifeq ($(TW_DISABLE_TTF), true) $(warning ****************************************************************************) $(warning * TW_DISABLE_TTF support has been deprecated in TWRP. *) diff --git a/minuitwrp/events.cpp b/minuitwrp/events.cpp index 955acf31..7e5bc42e 100755 --- a/minuitwrp/events.cpp +++ b/minuitwrp/events.cpp @@ -128,6 +128,7 @@ int write_to_file(const std::string& fn, const std::string& line) { } #ifndef TW_NO_HAPTICS +#ifndef TW_HAPTICS_TSPDRV int vibrate(int timeout_ms) { if (timeout_ms > 10000) timeout_ms = 1000; @@ -149,6 +150,7 @@ int vibrate(int timeout_ms) return 0; } #endif +#endif /* Returns empty tokens */ static char *vk_strtok_r(char *str, const char *delim, char **save_str) diff --git a/minuitwrp/tspdrv.cpp b/minuitwrp/tspdrv.cpp new file mode 100644 index 00000000..6967cd59 --- /dev/null +++ b/minuitwrp/tspdrv.cpp @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tspdrv.h" + +int tspdrv_initialized = 0; +int tspdrv_file_desc; +int tspdrv_numActuators = 0; + +int initialize_tspdrv() +{ + // Open device file as read/write for ioctl and write + tspdrv_file_desc = open(TSPDRV, O_RDWR); + if(tspdrv_file_desc < 0) + { + printf("Failed to open device file: %s", TSPDRV); + return -1; + } + + // create default device parameters + device_parameter dev_param1 { 0, VIBE_KP_CFG_FREQUENCY_PARAM1, 0}; + device_parameter dev_param2 { 0, VIBE_KP_CFG_FREQUENCY_PARAM2, 0}; + device_parameter dev_param3 { 0, VIBE_KP_CFG_FREQUENCY_PARAM3, 0}; + device_parameter dev_param4 { 0, VIBE_KP_CFG_FREQUENCY_PARAM4, 400}; + device_parameter dev_param5 { 0, VIBE_KP_CFG_FREQUENCY_PARAM5, 13435}; + device_parameter dev_param6 { 0, VIBE_KP_CFG_FREQUENCY_PARAM6, 0}; + device_parameter dev_param_update_rate {0, VIBE_KP_CFG_UPDATE_RATE_MS, 5}; + + // Set magic number for vibration driver, wont allow us to write data without! + int ret = ioctl(tspdrv_file_desc, TSPDRV_SET_MAGIC_NUMBER, TSPDRV_MAGIC_NUMBER); + if(ret != 0) + { + printf("Failed to set magic number"); + return -ret; + } + + // Set default device parameter 1 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param1); + if(ret != 0) + { + printf("Failed to set device parameter 1"); + return -ret; + } + + // Set default device parameter 2 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param2); + if(ret != 0) + { + printf("Failed to set device parameter 2"); + return -ret; + } + + // Set default device parameter 3 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param3); + if(ret != 0) + { + printf("Failed to set device parameter 3"); + return -ret; + } + + // Set default device parameter 4 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param4); + if(ret != 0) + { + printf("Failed to set device parameter 4"); + return -ret; + } + + // Set default device parameter 5 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param5); + if(ret != 0) + { + printf("Failed to set device parameter 5"); + return -ret; + } + + // Set default device parameter 6 + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param6); + if(ret != 0) + { + printf("Failed to set device parameter 6"); + return -ret; + } + + // Set default device parameter update rate + ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param_update_rate); + if(ret != 0) + { + printf("Failed to set device parameter update rate"); + return -ret; + } + + // Get number of actuators the device has + ret = ioctl(tspdrv_file_desc, TSPDRV_GET_NUM_ACTUATORS, 0); + if(ret == 0) + { + printf("No actuators found!"); + return -2; + } + + tspdrv_numActuators = ret; + tspdrv_initialized = 1; + return 0; +} + +int tspdrv_off() { + + for(int32_t i = 0; i < tspdrv_numActuators; i++) + { + int32_t ret = ioctl(tspdrv_file_desc, TSPDRV_DISABLE_AMP, i); + if(ret != 0) + { + printf("Failed to deactivate Actuator with index %d", i); + return -1; + } + } + + return 0; +} + +int vibrate(int timeout_ms) +{ + double BUFFER_ENTRIES_PER_MS = 8.21; + uint8_t DEFAULT_AMPLITUDE = 127; + int32_t OUTPUT_BUFFER_SIZE = 40; + + if(!tspdrv_initialized) + { + printf("Initializing TSPDRV\n"); + if(initialize_tspdrv() == 0) + { + printf("TSPDRV initialized\n"); + } + } + + // Calculate needed buffer entries + int32_t bufferSize = (int32_t) round(BUFFER_ENTRIES_PER_MS * timeout_ms); + VibeUInt8 fullBuffer[bufferSize]; + + // turn previous vibrations off + tspdrv_off(); + + for(int32_t i = 0; i < bufferSize; i++) + { + // The vibration is a sine curve, the negative parts are 255 + negative value + fullBuffer[i] = (VibeUInt8) (DEFAULT_AMPLITUDE * sin(i/BUFFER_ENTRIES_PER_MS)); + } + + // Amount of buffer arrays with size of OUTPUT_BUFFER_SIZE + int32_t numBuffers = (int32_t) ceil((double)bufferSize / (double)OUTPUT_BUFFER_SIZE); + VibeUInt8 outputBuffers[numBuffers][OUTPUT_BUFFER_SIZE]; + memset(outputBuffers, 0, sizeof(outputBuffers)); // zero the array before we fill it with values + + for(int32_t i = 0; i < bufferSize; i++) + { + // split fullBuffer into multiple smaller buffers with size OUTPUT_BUFFER_SIZE + outputBuffers[i/OUTPUT_BUFFER_SIZE][i%OUTPUT_BUFFER_SIZE] = fullBuffer[i]; + } + + for(int32_t i = 0; i < tspdrv_numActuators; i++) + { + for(int32_t j = 0; j < numBuffers; j++) + { + char output[OUTPUT_BUFFER_SIZE + SPI_HEADER_SIZE]; + memset(output, 0, sizeof(output)); + output[0] = i; // first byte is actuator index + output[1] = 8; // per definition has to be 8 + output[2] = OUTPUT_BUFFER_SIZE; // size of the following output buffer + for(int32_t k = 3; k < OUTPUT_BUFFER_SIZE+3; k++) + { + output[k] = outputBuffers[j][k-3]; + } + // write the buffer to the device + write(tspdrv_file_desc, output, sizeof(output)); + if((j+1) % 4 == 0) + { + // every 4 buffers, but not the first if theres only 1, we send an ENABLE_AMP signal + int32_t ret = ioctl(tspdrv_file_desc, TSPDRV_ENABLE_AMP, i); + if(ret != 0) + { + printf("Failed to activate Actuator with index %d", i); + return -1; + } + } + } + } + return 0; +} \ No newline at end of file diff --git a/minuitwrp/tspdrv.h b/minuitwrp/tspdrv.h new file mode 100644 index 00000000..afb294ee --- /dev/null +++ b/minuitwrp/tspdrv.h @@ -0,0 +1,100 @@ +/* +** ========================================================================= +** File: +** tspdrv.h +** +** Description: +** Constants and type definitions for the TouchSense Kernel Module. +** +** Portions Copyright (c) 2008-2017 Immersion Corporation. All Rights Reserved. +** +** This file contains Original Code and/or Modifications of Original Code +** as defined in and that are subject to the GNU Public License v2 - +** (the 'License'). You may not use this file except in compliance with the +** License. You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or contact +** TouchSenseSales@immersion.com. +** +** The Original Code and all software distributed under the License are +** distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +** EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES, +** INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see +** the License for the specific language governing rights and limitations +** under the License. +** ========================================================================= +*/ + +#ifndef _TSPDRV_H +#define _TSPDRV_H + +/* Constants */ +#define MODULE_NAME "tspdrv" +#define TSPDRV "/dev/tspdrv" +#define TSPDRV_MAGIC_NUMBER 0x494D4D52 +#define TSPDRV_IOCTL_GROUP 0x52 +#define TSPDRV_STOP_KERNEL_TIMER _IO(TSPDRV_IOCTL_GROUP, 1) /* obsolete, may be removed in future */ +#define TSPDRV_SET_MAGIC_NUMBER _IO(TSPDRV_IOCTL_GROUP, 2) +#define TSPDRV_ENABLE_AMP _IO(TSPDRV_IOCTL_GROUP, 3) +#define TSPDRV_DISABLE_AMP _IO(TSPDRV_IOCTL_GROUP, 4) +#define TSPDRV_GET_NUM_ACTUATORS _IO(TSPDRV_IOCTL_GROUP, 5) +#define TSPDRV_SET_DEVICE_PARAMETER _IO(TSPDRV_IOCTL_GROUP, 6) +#define TSPDRV_SET_DBG_LEVEL _IO(TSPDRV_IOCTL_GROUP, 7) +#define TSPDRV_GET_DBG_LEVEL _IO(TSPDRV_IOCTL_GROUP, 8) +#define TSPDRV_SET_RUNTIME_RECORD_FLAG _IO(TSPDRV_IOCTL_GROUP, 9) +#define TSPDRV_GET_RUNTIME_RECORD_FLAG _IO(TSPDRV_IOCTL_GROUP, 10) +#define TSPDRV_SET_RUNTIME_RECORD_BUF_SIZE _IO(TSPDRV_IOCTL_GROUP, 11) +#define TSPDRV_GET_RUNTIME_RECORD_BUF_SIZE _IO(TSPDRV_IOCTL_GROUP, 12) +#define TSPDRV_GET_PARAM_FILE_ID _IO(TSPDRV_IOCTL_GROUP, 13) +#define TSPDRV_GET_DEVICE_STATUS _IO(TSPDRV_IOCTL_GROUP, 14) +/* +** Frequency constant parameters to control force output values and signals. +*/ +#define VIBE_KP_CFG_FREQUENCY_PARAM1 85 +#define VIBE_KP_CFG_FREQUENCY_PARAM2 86 +#define VIBE_KP_CFG_FREQUENCY_PARAM3 87 +#define VIBE_KP_CFG_FREQUENCY_PARAM4 88 +#define VIBE_KP_CFG_FREQUENCY_PARAM5 89 +#define VIBE_KP_CFG_FREQUENCY_PARAM6 90 + +/* +** Force update rate in milliseconds. +*/ +#define VIBE_KP_CFG_UPDATE_RATE_MS 95 + +#define VIBE_MAX_DEVICE_NAME_LENGTH 64 +#define SPI_HEADER_SIZE 3 /* DO NOT CHANGE - SPI buffer header size */ +#define VIBE_OUTPUT_SAMPLE_SIZE 50 /* DO NOT CHANGE - maximum number of samples */ +#define MAX_DEBUG_BUFFER_LENGTH 1024 + +typedef int8_t VibeInt8; +typedef u_int8_t VibeUInt8; +typedef int16_t VibeInt16; +typedef u_int16_t VibeUInt16; +typedef int32_t VibeInt32; +typedef u_int32_t VibeUInt32; +typedef u_int8_t VibeBool; +typedef VibeInt32 VibeStatus; + +/* Device parameters sent to the kernel module, tspdrv.ko */ +typedef struct +{ + VibeInt32 nDeviceIndex; + VibeInt32 nDeviceParamID; + VibeInt32 nDeviceParamValue; +} device_parameter; + +typedef struct +{ + VibeUInt8 nActuatorIndex; /* 1st byte is actuator index */ + VibeUInt8 nBitDepth; /* 2nd byte is bit depth */ + VibeUInt8 nBufferSize; /* 3rd byte is data size */ + VibeUInt8 dataBuffer[40]; +} actuator_samples_buffer; + +/* Error and Return value codes */ +#define VIBE_S_SUCCESS 0 /* Success */ +#define VIBE_E_FAIL -4 /* Generic error */ + +#endif /* _TSPDRV_H */