kernel_samsung_a34x-permissive/drivers/sensorhub/sensor/scontext.c
2024-04-28 15:51:13 +02:00

417 lines
10 KiB
C

/*
* 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/slab.h>
#include "../comm/shub_comm.h"
#include "../comm/shub_iio.h"
#include "../utility/shub_utility.h"
#include "../sensormanager/shub_sensor.h"
#include "../sensormanager/shub_sensor_manager.h"
#include "../sensormanager/shub_sensor_type.h"
#include "../sensorhub/shub_device.h"
#include "scontext_cmd.h"
#define BIG_DATA_SIZE 256
#define PRINT_TRUNCATE 6
#define SCONTEXT_NAME_MAX 30
#define SCONTEXT_DATA_LEN 56
#define SCONTEXT_HEADER_LEN 8
#define RESET_REASON_KERNEL_RESET 0x01
#define RESET_REASON_MCU_CRASHED 0x02
#define RESET_REASON_SYSFS_REQUEST 0x03
#define RESET_REASON_HUB_REQUEST 0x04
void shub_scontext_log(const char *func_name, const char *data, int length)
{
char buf[6];
char *log_str;
int log_size, i;
if (likely(length <= BIG_DATA_SIZE))
log_size = length;
else
log_size = PRINT_TRUNCATE * 2 + 1;
log_size = sizeof(buf) * log_size + 1;
log_str = kzalloc(log_size, GFP_ATOMIC);
if (unlikely(!log_str)) {
shub_errf("allocate memory for data log err");
return;
}
for (i = 0; i < length; i++) {
if (length < BIG_DATA_SIZE || i < PRINT_TRUNCATE || i >= length - PRINT_TRUNCATE) {
snprintf(buf, sizeof(buf), "0x%x", (unsigned char)data[i]);
strlcat(log_str, buf, log_size);
if (i < length - 1)
strlcat(log_str, ", ", log_size);
}
if (length > BIG_DATA_SIZE && i == PRINT_TRUNCATE)
strlcat(log_str, "..., ", log_size);
}
shub_info("%s(%d): %s", func_name, length, log_str);
kfree(log_str);
}
void shub_report_scontext_data(char *data, u32 data_len)
{
u16 start, end;
u64 timestamp;
char buf[SCONTEXT_HEADER_LEN + SCONTEXT_DATA_LEN] = {0,};
shub_scontext_log(__func__, data, data_len);
if (data[0] == 0x01 && data[1] == 0x01) {
int type = data[2] + SENSOR_TYPE_SS_BASE;
struct shub_sensor *sensor = get_sensor(type);
if (sensor) {
sensor->event_buffer.timestamp = get_current_timestamp();
sensor->event_buffer.received_timestamp = sensor->event_buffer.timestamp;
}
}
start = 0;
memcpy(buf, &data_len, sizeof(u32));
timestamp = get_current_timestamp();
while (start < data_len) {
if (start + SCONTEXT_DATA_LEN < data_len) {
end = start + SCONTEXT_DATA_LEN - 1;
} else {
memset(buf + SCONTEXT_HEADER_LEN, 0, SCONTEXT_DATA_LEN);
end = data_len - 1;
}
memcpy(buf + sizeof(data_len), &start, sizeof(u16));
memcpy(buf + sizeof(data_len) + sizeof(start), &end, sizeof(u16));
memcpy(buf + SCONTEXT_HEADER_LEN, data + start, end - start + 1);
shub_report_sensordata(SENSOR_TYPE_SCONTEXT, timestamp, buf,
get_sensor(SENSOR_TYPE_SCONTEXT)->report_event_size);
start = end + 1;
}
}
void shub_report_scontext_notice_data(char notice)
{
char notice_buf[4] = {0x02, 0x01, 0x00, 0x00};
int len = 3;
notice_buf[2] = notice;
if (notice == SCONTEXT_NOTIFY_HUB_RESET) {
struct reset_info_t reset_info = get_reset_info();
len = 4;
if (reset_info.reason == RESET_TYPE_KERNEL_SYSFS)
notice_buf[3] = RESET_REASON_SYSFS_REQUEST;
else if (reset_info.reason == RESET_TYPE_KERNEL_NO_EVENT)
notice_buf[3] = RESET_REASON_KERNEL_RESET;
else if (reset_info.reason == RESET_TYPE_KERNEL_COM_FAIL)
notice_buf[3] = RESET_REASON_KERNEL_RESET;
else if (reset_info.reason == RESET_TYPE_HUB_CRASHED)
notice_buf[3] = RESET_REASON_MCU_CRASHED;
else if (reset_info.reason == RESET_TYPE_HUB_NO_EVENT)
notice_buf[3] = RESET_REASON_HUB_REQUEST;
}
shub_report_scontext_data(notice_buf, len);
if (notice == SCONTEXT_NOTIFY_HUB_RESET)
shub_infof("reset");
else
shub_errf("invalid notice(0x%x)", notice);
}
int convert_ap_status(int command)
{
int ret = -1;
switch (command) {
case SCONTEXT_AP_STATUS_SHUTDOWN:
ret = AP_SHUTDOWN;
break;
case SCONTEXT_AP_STATUS_LCD_ON:
ret = LCD_ON;
break;
case SCONTEXT_AP_STATUS_LCD_OFF:
ret = LCD_OFF;
break;
case SCONTEXT_AP_STATUS_POW_CONNECTED:
ret = POW_CONNECTED;
break;
case SCONTEXT_AP_STATUS_POW_DISCONNECTED:
ret = POW_DISCONNECTED;
break;
case SCONTEXT_AP_STATUS_CALL_IDLE:
ret = CALL_IDLE;
break;
case SCONTEXT_AP_STATUS_CALL_ACTIVE:
ret = CALL_ACTIVE;
break;
}
return ret;
}
int shub_scontext_send_cmd(const char *buf, int count)
{
int ret = 0;
int convert_status = 0;
struct shub_data_t *shub_data = get_shub_data();
convert_status = convert_ap_status(buf[2]);
if (convert_status < 0) {
shub_errf("INST_LIB_NOTI err(%d)", buf[2]);
return -EINVAL;
}
ret = shub_send_status(convert_status);
if (buf[2] == SCONTEXT_AP_STATUS_LCD_ON || buf[2] == SCONTEXT_AP_STATUS_LCD_OFF)
shub_data->lcd_status = convert_status;
return ret;
}
#define SCONTEXT_VALUE_CURRENTSYSTEMTIME 0x0E
#define SCONTEXT_VALUE_PEDOMETER_USERHEIGHT 0x12
#define SCONTEXT_VALUE_PEDOMETER_USERWEIGHT 0x13
#define SCONTEXT_VALUE_PEDOMETER_USERGENDER 0x14
#define SCONTEXT_VALUE_PEDOMETER_INFOUPDATETIME 0x15
int convert_scontext_putvalue_subcmd(int subcmd)
{
int ret = -1;
switch (subcmd) {
case SCONTEXT_VALUE_CURRENTSYSTEMTIME:
ret = CURRENT_SYSTEM_TIME;
break;
case SCONTEXT_VALUE_PEDOMETER_USERHEIGHT:
ret = PEDOMETER_USERHEIGHT;
break;
case SCONTEXT_VALUE_PEDOMETER_USERWEIGHT:
ret = PEDOMETER_USERWEIGHT;
break;
case SCONTEXT_VALUE_PEDOMETER_USERGENDER:
ret = PEDOMETER_USERGENDER;
break;
case SCONTEXT_VALUE_PEDOMETER_INFOUPDATETIME:
ret = PEDOMETER_INFOUPDATETIME;
break;
default:
ret = subcmd;
}
return ret;
}
int convert_scontext_getvalue_subcmd(int subcmd)
{
int ret = -1;
switch (subcmd) {
case SCONTEXT_VALUE_CURRENTSTATUS:
ret = LIBRARY_CURRENTSTATUS;
break;
case SCONTEXT_VALUE_CURRENTSTATUS_BATCH:
ret = LIBRARY_CURRENTSTATUS_BATCH;
break;
case SCONTEXT_VALUE_VERSIONINFO:
ret = LIBRARY_VERSIONINFO;
break;
default:
ret = subcmd;
}
return ret;
}
void get_ss_sensor_name(int type, char *buf, int buf_size)
{
memset(buf, 0, buf_size);
switch (type) {
case SENSOR_TYPE_SS_PEDOMETER:
strncpy(buf, "pedometer", buf_size);
break;
case SENSOR_TYPE_SS_STEP_COUNT_ALERT:
strncpy(buf, "step count alert", buf_size);
break;
case SENSOR_TYPE_SS_AUTO_ROTATION:
strncpy(buf, "auto rotation", buf_size);
break;
case SENSOR_TYPE_SS_SLOCATION:
strncpy(buf, "slocation", buf_size);
break;
case SENSOR_TYPE_SS_MOVEMENT:
strncpy(buf, "smart alert", buf_size);
break;
case SENSOR_TYPE_SS_ACTIVITY_TRACKER:
strncpy(buf, "activity tracker", buf_size);
break;
case SENSOR_TYPE_SS_DPCM:
strncpy(buf, "dpcm", buf_size);
break;
case SENSOR_TYPE_SS_SENSOR_STATUS_CHECK:
strncpy(buf, "sensor status check", buf_size);
break;
case SENSOR_TYPE_SS_ACTIVITY_CALIBRATION:
strncpy(buf, "activity calibration", buf_size);
break;
case SENSOR_TYPE_SS_DEVICE_POSITION:
strncpy(buf, "device position", buf_size);
break;
case SENSOR_TYPE_SS_CHANGE_LOCATION_TRIGGER:
strncpy(buf, "change location trigger", buf_size);
break;
case SENSOR_TYPE_SS_FREE_FALL_DETECTION:
strncpy(buf, "free fall detection", buf_size);
break;
}
}
int shub_scontext_send_instruction(const char *buf, int count)
{
char cmd, type, sub_cmd = 0;
char *buffer = (char *)(buf + 2);
int length = count - 2;
char name[SCONTEXT_NAME_MAX] = "";
if (buf[0] == SCONTEXT_INST_LIBRARY_REMOVE) {
cmd = CMD_REMOVE;
type = buf[1] + SENSOR_TYPE_SS_BASE;
if (type < SENSOR_TYPE_SS_MAX) {
get_ss_sensor_name(type, name, sizeof(name));
shub_infof("REMOVE LIB %s, type %d", name, type);
return disable_sensor(type, buffer, length);
} else {
return -EINVAL;
}
} else if (buf[0] == SCONTEXT_INST_LIBRARY_ADD) {
cmd = CMD_ADD;
type = buf[1] + SENSOR_TYPE_SS_BASE;
if (type < SENSOR_TYPE_SS_MAX) {
get_ss_sensor_name(type, name, sizeof(name));
shub_infof("ADD LIB %s, type %d", name, type);
return enable_sensor(type, buffer, length);
} else {
return -EINVAL;
}
} else if (buf[0] == SCONTEXT_INST_LIB_SET_DATA) {
cmd = CMD_SETVALUE;
if (buf[1] != SCONTEXT_VALUE_LIBRARY_DATA) {
type = TYPE_HUB;
sub_cmd = convert_scontext_putvalue_subcmd(buf[1]);
} else {
type = buf[2] + SENSOR_TYPE_SS_BASE;
sub_cmd = LIBRARY_DATA;
length = count - 3;
if (length > 0)
buffer = (char *)(buf + 3);
else
buffer = NULL;
}
} else if (buf[0] == SCONTEXT_INST_LIB_GET_DATA) {
cmd = CMD_GETVALUE;
type = buf[1] + SENSOR_TYPE_SS_BASE;
sub_cmd = convert_scontext_getvalue_subcmd(buf[2]);
length = count - 3;
if (length > 0)
buffer = (char *)(buf + 3);
else
buffer = NULL;
} else {
shub_errf("0x%x is not supported", buf[0]);
return -EINVAL;
}
return shub_send_command(cmd, type, sub_cmd, buffer, length);
}
void init_scontext_enable_state(void)
{
int type;
for (type = SENSOR_TYPE_SS_BASE; type < SENSOR_TYPE_SS_MAX; type++) {
struct shub_sensor *sensor = get_sensor(type);
if (sensor) {
mutex_lock(&sensor->enabled_mutex);
sensor->enabled_cnt = 0;
sensor->enabled = false;
mutex_unlock(&sensor->enabled_mutex);
}
}
}
void disable_scontext_all(void)
{
int type;
char buf[2];
for (type = SENSOR_TYPE_SS_BASE; type < SENSOR_TYPE_SS_MAX; type++) {
struct shub_sensor *sensor = get_sensor(type);
if (sensor && sensor->enabled) {
/*
* enabled_cnt may be 1 or more. ref) EXTRA_EXTERNAL_CLIENT_REMOVED
* if count > 1, buffer should not be null. So, set enabled_cnt to 1 intentionally.
*/
mutex_lock(&sensor->enabled_mutex);
sensor->enabled_cnt = 1;
mutex_unlock(&sensor->enabled_mutex);
disable_sensor(type, buf, sizeof(buf));
}
}
}
void print_scontext_debug(void)
{
/* print nothing for debug */
}
static struct sensor_funcs scontext_sensor_funcs = {
.print_debug = print_scontext_debug,
};
int init_scontext(bool en)
{
int ret = 0;
struct shub_sensor *sensor = get_sensor(SENSOR_TYPE_SCONTEXT);
if (!sensor)
return 0;
if (en) {
ret = init_default_func(sensor, "scontext_iio", 0, 64, 64);
sensor->funcs = &scontext_sensor_funcs;
} else {
destroy_default_func(sensor);
}
return ret;
}