2024-04-28 06:49:01 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2020, Samsung Electronics Co. Ltd. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
|
|
#include "../comm/shub_comm.h"
|
|
|
|
#include "../sensor/scontext.h"
|
|
|
|
#include "../sensormanager/shub_sensor.h"
|
|
|
|
#include "../sensormanager/shub_sensor_manager.h"
|
|
|
|
#include "../sensorhub/shub_device.h"
|
|
|
|
#include "../utility/shub_utility.h"
|
|
|
|
#include "../utility/shub_dev_core.h"
|
|
|
|
#include "../utility/sensor_core.h"
|
|
|
|
#include "../vendor/shub_vendor.h"
|
|
|
|
#include "shub_sensor_dump.h"
|
|
|
|
#include "shub_system_checker.h"
|
|
|
|
#include "shub_debug.h"
|
|
|
|
|
|
|
|
#define TIMEINFO_SIZE 50
|
|
|
|
#define SUPPORT_SENSORLIST \
|
|
|
|
do { \
|
|
|
|
{SENSOR_TYPE_ACCELEROMETER, SENSOR_TYPE_GYROSCOPE, SENSOR_TYPE_GEOMAGNETIC_FIELD, SENSOR_TYPE_PRESSURE, \
|
|
|
|
SENSOR_TYPE_PROXIMITY, SENSOR_TYPE_LIGHT} \
|
|
|
|
} while (0)
|
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
#if IS_ENABLED(CONFIG_SENSORS_GRIP_FAILURE_DEBUG)
|
|
|
|
static void sensor_get_grip_info(void)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < GRIP_MAX_CNT; i++)
|
|
|
|
pr_err("GRIP%d_REASON : %d\n", i, grip_error[i]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Caution !
|
|
|
|
* Do not change the format. ex) !@#REG_DUMP!@#, @@TYPE:1##
|
|
|
|
* Big data parses the data.
|
|
|
|
*/
|
2024-04-28 06:49:01 -07:00
|
|
|
static ssize_t sensor_dump_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
char **sensor_dump_data = get_sensor_dump_data();
|
|
|
|
int types[] = SENSOR_DUMP_SENSOR_LIST;
|
|
|
|
char str_no_sensor_dump[] = "there is no sensor dump";
|
|
|
|
int i = 0, ret;
|
|
|
|
char *sensor_dump;
|
2024-04-28 06:51:13 -07:00
|
|
|
char temp[sensor_dump_length(DUMPREGISTER_MAX_SIZE) + LENGTH_SENSOR_TYPE_MAX] = {0,};
|
2024-04-28 06:49:01 -07:00
|
|
|
char time_temp[TIMEINFO_SIZE] = "";
|
|
|
|
char *time_info;
|
|
|
|
char str_no_registered_sensor[] = "there is no registered sensor";
|
|
|
|
char reset_info[TIMEINFO_SIZE*2 + 20] = "Sensor Hub Reset : ";
|
2024-04-28 06:51:13 -07:00
|
|
|
char str_reg_dump_filter[] = "!@#REG_DUMP!@#";
|
2024-04-28 06:49:01 -07:00
|
|
|
int cnt = 0;
|
|
|
|
struct shub_sensor *sensor;
|
|
|
|
|
|
|
|
sensor_dump = kzalloc(
|
2024-04-28 06:51:13 -07:00
|
|
|
(sensor_dump_length(DUMPREGISTER_MAX_SIZE) + LENGTH_SENSOR_TYPE_MAX) * (ARRAY_SIZE(types)), GFP_KERNEL);
|
2024-04-28 06:49:01 -07:00
|
|
|
|
|
|
|
if (!sensor_dump) {
|
|
|
|
shub_errf("fail to allocate memory for dump buffer");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(types); i++) {
|
|
|
|
if (sensor_dump_data[types[i]] != NULL) {
|
2024-04-28 06:51:13 -07:00
|
|
|
snprintf(temp, sizeof(temp), "@@TYPE:%d##\n%s", types[i], sensor_dump_data[types[i]]);
|
2024-04-28 06:49:01 -07:00
|
|
|
strcpy(&sensor_dump[(int)strlen(sensor_dump)], temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_reset_count() > 0) {
|
|
|
|
struct reset_info_t reset = get_reset_info();
|
|
|
|
|
|
|
|
if (reset.reason == RESET_TYPE_KERNEL_SYSFS)
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info),
|
|
|
|
"Kernel Sysfs\n");
|
|
|
|
else if (reset.reason == RESET_TYPE_KERNEL_NO_EVENT)
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info),
|
|
|
|
"Kernel No Event\n");
|
|
|
|
else if (reset.reason == RESET_TYPE_HUB_NO_EVENT)
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info),
|
|
|
|
"Hub Req No Event\n");
|
|
|
|
else if (reset.reason == RESET_TYPE_KERNEL_COM_FAIL)
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info),
|
|
|
|
"Com Fail\n");
|
|
|
|
else
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info),
|
|
|
|
"HUB Reset\n");
|
|
|
|
strcpy(&reset_info[(int)strlen(reset_info)], time_temp);
|
|
|
|
|
|
|
|
snprintf(time_temp, sizeof(time_temp),
|
|
|
|
" %04d%02d%02d %02d:%02d:%02d UTC(%llu)\n", reset.time.tm_year + 1900,
|
|
|
|
reset.time.tm_mon + 1, reset.time.tm_mday, reset.time.tm_hour, reset.time.tm_min,
|
|
|
|
reset.time.tm_sec, reset.timestamp);
|
|
|
|
strncpy(&reset_info[(int)strlen(reset_info)], time_temp, sizeof(reset_info) - (int)strlen(reset_info));
|
|
|
|
} else {
|
|
|
|
snprintf(&reset_info[(int)strlen(reset_info)], sizeof(reset_info) - (int)strlen(reset_info), " None\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < SENSOR_TYPE_MAX; i++) {
|
|
|
|
sensor = get_sensor(i);
|
|
|
|
if (sensor && sensor->enable_timestamp != 0)
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cnt > 0) {
|
|
|
|
time_info = kzalloc(TIMEINFO_SIZE * 3 * cnt, GFP_KERNEL);
|
|
|
|
if (!time_info) {
|
|
|
|
shub_infof("fail to allocate memory for time info");
|
|
|
|
time_info = NULL;
|
|
|
|
cnt = 0;
|
|
|
|
goto print_sensordump;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < SENSOR_TYPE_MAX; i++) {
|
|
|
|
sensor = get_sensor(i);
|
|
|
|
if (sensor && sensor->enable_timestamp != 0) {
|
|
|
|
struct rtc_time regi_tm = sensor->enable_time;
|
|
|
|
struct rtc_time unregi_tm = sensor->disable_time;
|
|
|
|
char name[SENSOR_NAME_MAX] = "";
|
|
|
|
|
|
|
|
memcpy(name, sensor->name, SENSOR_NAME_MAX);
|
|
|
|
|
|
|
|
memset(time_temp, 0, sizeof(time_temp));
|
|
|
|
snprintf(time_temp, TIMEINFO_SIZE, "%3d %s\n", i, name);
|
|
|
|
strcpy(&time_info[(int)strlen(time_info)], time_temp);
|
|
|
|
|
|
|
|
if (sensor->enabled) {
|
|
|
|
if (sensor->disable_timestamp != 0) {
|
|
|
|
snprintf(time_temp, TIMEINFO_SIZE,
|
|
|
|
"- %04d%02d%02d %02d:%02d:%02d UTC(%llu)\n",
|
|
|
|
unregi_tm.tm_year + 1900, unregi_tm.tm_mon + 1,
|
|
|
|
unregi_tm.tm_mday, unregi_tm.tm_hour, unregi_tm.tm_min,
|
|
|
|
unregi_tm.tm_sec, sensor->disable_timestamp);
|
|
|
|
strcpy(&time_info[(int)strlen(time_info)], time_temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(time_temp, TIMEINFO_SIZE,
|
|
|
|
"+ %04d%02d%02d %02d:%02d:%02d UTC(%llu)\n",
|
|
|
|
regi_tm.tm_year + 1900, regi_tm.tm_mon + 1, regi_tm.tm_mday,
|
|
|
|
regi_tm.tm_hour, regi_tm.tm_min, regi_tm.tm_sec,
|
|
|
|
sensor->enable_timestamp);
|
|
|
|
strcpy(&time_info[(int)strlen(time_info)], time_temp);
|
|
|
|
} else {
|
|
|
|
snprintf(time_temp, TIMEINFO_SIZE,
|
|
|
|
"+ %04d%02d%02d %02d:%02d:%02d UTC(%llu)\n",
|
|
|
|
regi_tm.tm_year + 1900, regi_tm.tm_mon + 1, regi_tm.tm_mday,
|
|
|
|
regi_tm.tm_hour, regi_tm.tm_min, regi_tm.tm_sec,
|
|
|
|
sensor->enable_timestamp);
|
|
|
|
strcpy(&time_info[(int)strlen(time_info)], time_temp);
|
|
|
|
|
|
|
|
if (sensor->disable_timestamp != 0) {
|
|
|
|
snprintf(time_temp, TIMEINFO_SIZE,
|
|
|
|
"- %04d%02d%02d %02d:%02d:%02d UTC(%llu)\n",
|
|
|
|
unregi_tm.tm_year + 1900, unregi_tm.tm_mon + 1,
|
|
|
|
unregi_tm.tm_mday, unregi_tm.tm_hour, unregi_tm.tm_min,
|
|
|
|
unregi_tm.tm_sec, sensor->disable_timestamp);
|
|
|
|
strcpy(&time_info[(int)strlen(time_info)], time_temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
time_info = str_no_registered_sensor;
|
|
|
|
}
|
|
|
|
|
|
|
|
print_sensordump:
|
|
|
|
if ((int)strlen(sensor_dump) == 0)
|
|
|
|
ret = snprintf(buf, PAGE_SIZE, "%s\n%s\n%s\n", str_no_sensor_dump, reset_info, time_info);
|
|
|
|
else
|
2024-04-28 06:51:13 -07:00
|
|
|
ret = snprintf(buf, PAGE_SIZE, "%s\n%s%s\n\n%s\n%s\n",
|
|
|
|
str_reg_dump_filter, sensor_dump, str_reg_dump_filter, reset_info, time_info);
|
2024-04-28 06:49:01 -07:00
|
|
|
|
|
|
|
kfree(sensor_dump);
|
|
|
|
if (cnt > 0)
|
|
|
|
kfree(time_info);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t sensor_dump_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int sensor_type, ret;
|
|
|
|
char name[SENSOR_NAME_MAX + 1] = {0,};
|
|
|
|
|
|
|
|
if (sscanf(buf, "%40s", name) != 1) // 40 : SENSOR_NAME_MAX
|
|
|
|
return -EINVAL;
|
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
clear_sensor_dump();
|
|
|
|
|
2024-04-28 06:49:01 -07:00
|
|
|
if ((strcmp(name, "all")) == 0) {
|
2024-04-28 06:51:13 -07:00
|
|
|
int type;
|
|
|
|
|
|
|
|
shub_errf("last event of sensors");
|
|
|
|
for (type = 0; type < SENSOR_TYPE_MAX; type++) {
|
|
|
|
print_sensor_debug(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
print_big_data();
|
|
|
|
|
2024-04-28 06:49:01 -07:00
|
|
|
sensorhub_save_ram_dump();
|
|
|
|
ret = send_all_sensor_dump_command();
|
|
|
|
} else {
|
|
|
|
if (strcmp(name, "accelerometer") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_ACCELEROMETER;
|
|
|
|
else if (strcmp(name, "gyroscope") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_GYROSCOPE;
|
|
|
|
else if (strcmp(name, "magnetic") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_GEOMAGNETIC_FIELD;
|
|
|
|
else if (strcmp(name, "pressure") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_PRESSURE;
|
|
|
|
else if (strcmp(name, "proximity") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_PROXIMITY;
|
|
|
|
else if (strcmp(name, "light") == 0)
|
|
|
|
sensor_type = SENSOR_TYPE_LIGHT;
|
|
|
|
else {
|
|
|
|
shub_errf("is not supported : %s", buf);
|
|
|
|
sensor_type = -1;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
ret = send_sensor_dump_command(sensor_type);
|
|
|
|
}
|
2024-04-28 06:51:13 -07:00
|
|
|
#if IS_ENABLED(CONFIG_SENSORS_GRIP_FAILURE_DEBUG)
|
|
|
|
sensor_get_grip_info();
|
|
|
|
#endif
|
2024-04-28 06:49:01 -07:00
|
|
|
return (ret == 0) ? size : ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t sensor_axis_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
int accel_position = -1;
|
|
|
|
int gyro_position = -1;
|
|
|
|
int mag_position = -1;
|
|
|
|
struct shub_sensor *sensor;
|
|
|
|
|
|
|
|
sensor = get_sensor(SENSOR_TYPE_ACCELEROMETER);
|
|
|
|
if (sensor)
|
|
|
|
accel_position = sensor->funcs->get_position();
|
|
|
|
|
|
|
|
sensor = get_sensor(SENSOR_TYPE_GYROSCOPE);
|
|
|
|
if (sensor)
|
|
|
|
gyro_position = sensor->funcs->get_position();
|
|
|
|
|
|
|
|
sensor = get_sensor(SENSOR_TYPE_GEOMAGNETIC_FIELD);
|
|
|
|
if (sensor)
|
|
|
|
mag_position = sensor->funcs->get_position();
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%d: %d\n%d: %d\n%d: %d\n",
|
|
|
|
SENSOR_TYPE_ACCELEROMETER, accel_position,
|
|
|
|
SENSOR_TYPE_GYROSCOPE, gyro_position,
|
|
|
|
SENSOR_TYPE_GEOMAGNETIC_FIELD, mag_position);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t sensor_axis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
struct shub_sensor *sensor;
|
|
|
|
int type = 0;
|
|
|
|
int position = 0;
|
|
|
|
|
|
|
|
sscanf(buf, "%9d,%9d", &type, &position);
|
|
|
|
|
|
|
|
if (position < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sensor = get_sensor(type);
|
|
|
|
if (!sensor) {
|
|
|
|
shub_errf("type %d is not suppoerted", type);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sensor->funcs->set_position(position);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool debug_enable[SHUB_LOG_MAX];
|
|
|
|
|
|
|
|
bool check_debug_log_state(int log_type)
|
|
|
|
{
|
|
|
|
return log_type < SHUB_LOG_MAX ? debug_enable[log_type] : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t debug_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%d %d\n",
|
|
|
|
debug_enable[SHUB_LOG_EVENT_TIMESTAMP], debug_enable[SHUB_LOG_DATA_PACKET]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t debug_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
|
|
{
|
2024-04-28 06:51:13 -07:00
|
|
|
char *input_str = NULL, *input_str_origin = NULL, *token = NULL;
|
2024-04-28 06:49:01 -07:00
|
|
|
unsigned int arg[5] = {0,};
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
shub_infof("%s", buf);
|
|
|
|
if (strlen(buf) == 0)
|
|
|
|
return size;
|
|
|
|
|
|
|
|
input_str = kzalloc(strlen(buf) + 1, GFP_KERNEL);
|
|
|
|
if (!input_str)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(input_str, buf, strlen(buf));
|
2024-04-28 06:51:13 -07:00
|
|
|
input_str_origin = input_str;
|
2024-04-28 06:49:01 -07:00
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
while (((token = strsep(&input_str, " ")) != NULL)) {
|
2024-04-28 06:49:01 -07:00
|
|
|
switch (index) {
|
|
|
|
case 0:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtoint(token, 10, &arg[0]) < 0)
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
break;
|
|
|
|
case 1:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtoint(token, 10, &arg[1]) < 0)
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index == 1) {
|
|
|
|
for (index = 0; index < SHUB_LOG_MAX; index++)
|
|
|
|
debug_enable[index] = arg[0] ? true : false;
|
|
|
|
} else if (arg[1] < SHUB_LOG_MAX) {
|
|
|
|
debug_enable[arg[1]] = arg[0] ? true : false;
|
|
|
|
}
|
|
|
|
exit:
|
2024-04-28 06:51:13 -07:00
|
|
|
kfree(input_str_origin);
|
2024-04-28 06:49:01 -07:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_SHUB_DEBUG
|
|
|
|
int htou8(char input)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if ('0' <= input && input <= '9')
|
|
|
|
return ret = input - '0';
|
|
|
|
else if ('a' <= input && input <= 'f')
|
|
|
|
return ret = input - 'a' + 10;
|
|
|
|
else if ('A' <= input && input <= 'F')
|
|
|
|
return ret = input - 'A' + 10;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char register_value[5];
|
|
|
|
|
|
|
|
static ssize_t make_command_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
u8 cmd = 0, type = 0, subcmd = 0;
|
|
|
|
char *send_buf = NULL;
|
|
|
|
int send_buf_len = 0;
|
|
|
|
unsigned int arg[10] = {0, };
|
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
char *input_str = NULL, *input_str_origin = NULL, *token = NULL;
|
2024-04-28 06:49:01 -07:00
|
|
|
int index = 0, i = 0;
|
|
|
|
|
|
|
|
shub_infof("%s", buf);
|
|
|
|
|
|
|
|
if (strlen(buf) == 0)
|
|
|
|
return size;
|
|
|
|
|
|
|
|
input_str = kzalloc(strlen(buf) + 1, GFP_KERNEL);
|
|
|
|
if (!input_str)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(input_str, buf, strlen(buf));
|
2024-04-28 06:51:13 -07:00
|
|
|
input_str_origin = input_str;
|
2024-04-28 06:49:01 -07:00
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
while (((token = strsep(&input_str, " ")) != NULL)) {
|
2024-04-28 06:49:01 -07:00
|
|
|
switch (index) {
|
|
|
|
case 0:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtou8(token, 10, &cmd) < 0) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("invalid cmd(%d)", cmd);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtou8(token, 10, &type) < 0) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("invalid type(%d)", type);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtou8(token, 10, &subcmd) < 0) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("invalid subcmd(%d)", subcmd);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (cmd == CMD_SETVALUE && subcmd == HUB_SYSTEM_CHECK) {
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtouint(token, 10, &arg[0])) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("parsing error");
|
|
|
|
goto exit;
|
|
|
|
}
|
2024-04-28 06:51:13 -07:00
|
|
|
} else if (cmd == CMD_ADD) {
|
|
|
|
send_buf_len = 8;
|
|
|
|
send_buf = kzalloc(send_buf_len, GFP_KERNEL);
|
|
|
|
if (kstrtouint(token, 10, &arg[0])) {
|
|
|
|
shub_errf("parssing error");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
memcpy(&send_buf[0], &arg[0], 4);
|
2024-04-28 06:49:01 -07:00
|
|
|
} else {
|
2024-04-28 06:51:13 -07:00
|
|
|
if ((strlen(token) - 1) % 2 != 0) {
|
|
|
|
shub_errf("not match buf len(%d) != %d", (int)strlen(token), send_buf_len);
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
}
|
2024-04-28 06:51:13 -07:00
|
|
|
send_buf_len = (strlen(token) - 1) / 2;
|
2024-04-28 06:49:01 -07:00
|
|
|
send_buf = kzalloc(send_buf_len, GFP_KERNEL);
|
|
|
|
if (!send_buf) {
|
|
|
|
shub_errf("fail to alloc memory");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < send_buf_len; i++) {
|
2024-04-28 06:51:13 -07:00
|
|
|
send_buf[i] = (u8)((htou8(token[2 * i]) << 4) | htou8(token[2 * i + 1]));
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_infof("[%d]:%d", i, send_buf[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (cmd == CMD_SETVALUE && subcmd == HUB_SYSTEM_CHECK) {
|
|
|
|
if (kstrtouint(token, 10, &arg[1])) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("parsing error");
|
|
|
|
goto exit;
|
|
|
|
}
|
2024-04-28 06:51:13 -07:00
|
|
|
} else if (cmd == CMD_ADD) {
|
|
|
|
if (kstrtouint(token, 10, &arg[1])) {
|
|
|
|
shub_errf("parssing error");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
memcpy(&send_buf[4], &arg[1], 4);
|
|
|
|
shub_infof("type : %d, sampling : %d, report : %d", type, arg[0], arg[1]);
|
|
|
|
} else {
|
|
|
|
shub_errf("unused input");
|
|
|
|
}
|
2024-04-28 06:49:01 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 2) {
|
|
|
|
shub_errf("need more input");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd == CMD_SETVALUE && subcmd == HUB_SYSTEM_CHECK) {
|
|
|
|
sensorhub_system_check(arg[0], arg[1]);
|
|
|
|
} else {
|
|
|
|
ret = shub_send_command(cmd, type, subcmd, send_buf, send_buf_len);
|
|
|
|
if (ret < 0) {
|
|
|
|
shub_errf("shub_send_command failed");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
kfree(send_buf);
|
2024-04-28 06:51:13 -07:00
|
|
|
kfree(input_str_origin);
|
2024-04-28 06:49:01 -07:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t register_rw_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
if (register_value[1] == 'r') {
|
|
|
|
return sprintf(buf, "sensor(%d) %c regi(0x%x) val(0x%x) ret(%d)\n",
|
|
|
|
register_value[0], register_value[1], register_value[2],
|
|
|
|
register_value[3], register_value[4]);
|
|
|
|
} else {
|
|
|
|
if (register_value[4] == true) {
|
|
|
|
return sprintf(buf, "sensor(%d) %c regi(0x%x) val(0x%x) SUCCESS\n",
|
|
|
|
register_value[0], register_value[1], register_value[2], register_value[3]);
|
|
|
|
} else {
|
|
|
|
return sprintf(buf, "sensor(%d) %c regi(0x%x) val(0x%x) FAIL\n",
|
|
|
|
register_value[0], register_value[1], register_value[2], register_value[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t register_rw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int index = 0, ret = 0;
|
|
|
|
u8 sensor_type, send_val[2];
|
|
|
|
char rw_cmd;
|
|
|
|
|
|
|
|
char input_str[20] = {0,};
|
2024-04-28 06:51:13 -07:00
|
|
|
char *tmp_str = NULL, *token = NULL;
|
2024-04-28 06:49:01 -07:00
|
|
|
|
|
|
|
if (strlen(buf) >= sizeof(input_str)) {
|
2024-04-28 06:51:13 -07:00
|
|
|
shub_errf("bufsize too long(%d)", (int)strlen(buf));
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(input_str, buf, strlen(buf));
|
2024-04-28 06:51:13 -07:00
|
|
|
tmp_str = input_str;
|
2024-04-28 06:49:01 -07:00
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
while (((token = strsep(&tmp_str, " ")) != NULL)) {
|
2024-04-28 06:49:01 -07:00
|
|
|
switch (index) {
|
|
|
|
case 0:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (kstrtou8(token, 10, &sensor_type) < 0 || (sensor_type >= SENSOR_TYPE_MAX)) {
|
2024-04-28 06:49:01 -07:00
|
|
|
shub_errf("invalid type(%d)", sensor_type);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
2024-04-28 06:51:13 -07:00
|
|
|
if (token[0] == 'r' || token[0] == 'w')
|
|
|
|
rw_cmd = token[0];
|
2024-04-28 06:49:01 -07:00
|
|
|
else {
|
2024-04-28 06:51:13 -07:00
|
|
|
shub_errf("invalid cmd(%c)", token[0]);
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2024-04-28 06:51:13 -07:00
|
|
|
if ((strlen(token) == 4) && token[0] != '0' && token[1] != 'x') {
|
|
|
|
shub_errf("invalid value(0xOO) %s", token);
|
2024-04-28 06:49:01 -07:00
|
|
|
goto exit;
|
|
|
|
}
|
2024-04-28 06:51:13 -07:00
|
|
|
send_val[index - 2] = (u8)((htou8(token[2]) << 4) | htou8(token[3]));
|
2024-04-28 06:49:01 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
register_value[0] = sensor_type;
|
|
|
|
register_value[1] = rw_cmd;
|
|
|
|
register_value[2] = send_val[0];
|
|
|
|
|
|
|
|
if (rw_cmd == 'r') {
|
|
|
|
char *rec_buf = NULL;
|
|
|
|
int rec_buf_len = 0;
|
|
|
|
|
|
|
|
ret = shub_send_command_wait(CMD_GETVALUE, sensor_type, SENSOR_REGISTER_RW,
|
|
|
|
1000, send_val, 1, &rec_buf, &rec_buf_len, false);
|
|
|
|
register_value[4] = true;
|
|
|
|
if (ret < 0) {
|
|
|
|
register_value[4] = false;
|
|
|
|
shub_errf("shub_send_command_wait fail %d", ret);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
register_value[3] = rec_buf[0];
|
|
|
|
|
|
|
|
kfree(rec_buf);
|
|
|
|
} else { /* rw_cmd == w */
|
|
|
|
ret = shub_send_command(CMD_SETVALUE, sensor_type, SENSOR_REGISTER_RW, send_val, 2);
|
|
|
|
register_value[3] = send_val[1];
|
|
|
|
register_value[4] = true;
|
|
|
|
if (ret < 0) {
|
|
|
|
register_value[4] = false;
|
|
|
|
shub_errf("shub_send_command fail %d", ret);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
#if IS_ENABLED(CONFIG_SENSORS_GRIP_FAILURE_DEBUG)
|
|
|
|
void update_grip_error(u8 idx, u32 error_state)
|
|
|
|
{
|
|
|
|
if (idx >= GRIP_MAX_CNT) {
|
|
|
|
pr_info("[FACTORY] %s dump is NULL \n", __func__,
|
|
|
|
idx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
grip_error[idx] = error_state;
|
|
|
|
pr_info("[FACTORY] %s [IC num %d] grip_error %d\n", __func__,
|
|
|
|
idx, error_state);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(update_grip_error);
|
|
|
|
static ssize_t grip_fail_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
int i = 0, j = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < GRIP_MAX_CNT; i++) {
|
|
|
|
j += snprintf(buf + j, PAGE_SIZE - j,
|
|
|
|
"\"GRIP%d_REASON\":\"%d\",",
|
|
|
|
i, grip_error[i]);
|
|
|
|
pr_info("[FACTORY] %s \"GRIP%d_REASON\":\"%d\",",
|
|
|
|
__func__, i, grip_error[i]);
|
|
|
|
grip_error[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-28 06:49:01 -07:00
|
|
|
static DEVICE_ATTR(sensor_dump, 0664, sensor_dump_show, sensor_dump_store);
|
|
|
|
static DEVICE_ATTR_RW(sensor_axis);
|
|
|
|
static DEVICE_ATTR_RW(debug_enable);
|
|
|
|
#ifdef CONFIG_SHUB_DEBUG
|
|
|
|
static DEVICE_ATTR(make_command, 0220, NULL, make_command_store);
|
|
|
|
static DEVICE_ATTR_RW(register_rw);
|
|
|
|
#endif
|
2024-04-28 06:51:13 -07:00
|
|
|
#if IS_ENABLED(CONFIG_SENSORS_GRIP_FAILURE_DEBUG)
|
|
|
|
static DEVICE_ATTR(grip_fail, 0440, grip_fail_show, NULL);
|
|
|
|
#endif
|
2024-04-28 06:49:01 -07:00
|
|
|
static struct device_attribute *shub_debug_attrs[] = {
|
|
|
|
&dev_attr_sensor_axis,
|
2024-04-28 06:51:13 -07:00
|
|
|
#if IS_ENABLED(CONFIG_SENSORS_GRIP_FAILURE_DEBUG)
|
|
|
|
&dev_attr_grip_fail,
|
|
|
|
#endif
|
2024-04-28 06:49:01 -07:00
|
|
|
&dev_attr_sensor_dump,
|
|
|
|
&dev_attr_debug_enable,
|
|
|
|
#ifdef CONFIG_SHUB_DEBUG
|
|
|
|
&dev_attr_make_command,
|
|
|
|
&dev_attr_register_rw,
|
|
|
|
#endif
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
int init_shub_debug_sysfs(void)
|
|
|
|
{
|
|
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sensor_device_create(&data->sysfs_dev, data, "ssp_sensor");
|
|
|
|
if (ret < 0) {
|
|
|
|
shub_errf("fail to creat ssp_sensor device");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = add_sensor_device_attr(data->sysfs_dev, shub_debug_attrs);
|
|
|
|
if (ret < 0)
|
|
|
|
shub_errf("fail to add shub debug attr");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove_shub_debug_sysfs(void)
|
|
|
|
{
|
|
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
|
|
|
|
remove_sensor_device_attr(data->sysfs_dev, shub_debug_attrs);
|
|
|
|
sensor_device_destroy(data->sysfs_dev);
|
|
|
|
}
|