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)
diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk
index 2b5650d..ac09e49 100644
--- a/minuitwrp/Android.mk
+++ b/minuitwrp/Android.mk
@@ -190,6 +190,11 @@
   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 955acf3..7e5bc42 100755
--- a/minuitwrp/events.cpp
+++ b/minuitwrp/events.cpp
@@ -128,6 +128,7 @@
 }
 
 #ifndef TW_NO_HAPTICS
+#ifndef TW_HAPTICS_TSPDRV
 int vibrate(int timeout_ms)
 {
     if (timeout_ms > 10000) timeout_ms = 1000;
@@ -149,6 +150,7 @@
     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 0000000..6967cd5
--- /dev/null
+++ b/minuitwrp/tspdrv.cpp
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cinttypes>
+#include <cmath>
+#include <iostream>
+#include <sys/ioctl.h>
+
+#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 0000000..afb294e
--- /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 */