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)
This commit is contained in:
LameMonster82
2020-06-04 13:31:12 +02:00
committed by bigbiff
parent 32cbabe413
commit 4ef96a6f9a
4 changed files with 300 additions and 0 deletions
+5
View File
@@ -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. *)
+2
View File
@@ -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)
+193
View File
@@ -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;
}
+100
View File
@@ -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 */