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:
@@ -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. *)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user