353 lines
12 KiB
C
Executable File
353 lines
12 KiB
C
Executable File
/*
|
|
* Copyright (C) 2018, 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/kernel.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include "ssp_debug.h"
|
|
#include "ssp_type_define.h"
|
|
#include "ssp_platform.h"
|
|
#include "ssp_comm.h"
|
|
#include "ssp_dump.h"
|
|
#include "ssp_data.h"
|
|
#include "ssp_scontext.h"
|
|
#include "ssp_cmd_define.h"
|
|
|
|
/* define */
|
|
#define SSP_DEBUG_TIMER_SEC (5 * HZ)
|
|
#define LIMIT_TIMEOUT_CNT 1
|
|
#define LIMIT_COMFAIL_CNT 3
|
|
|
|
int ssp_wait_event_timeout(struct ssp_waitevent *lock, int timeout)
|
|
{
|
|
int ret;
|
|
ret = wait_event_interruptible_timeout(lock->waitqueue, atomic_read(&lock->state), msecs_to_jiffies(timeout));
|
|
|
|
if(ret == 0)
|
|
return FAIL;
|
|
else
|
|
return SUCCESS;
|
|
}
|
|
|
|
void ssp_lock_wait_event(struct ssp_waitevent *lock)
|
|
{
|
|
atomic_set(&lock->state, 0);
|
|
}
|
|
|
|
void ssp_wake_up_wait_event(struct ssp_waitevent *lock)
|
|
{
|
|
atomic_set(&lock->state, 1);
|
|
wake_up_interruptible_sync(&lock->waitqueue);
|
|
}
|
|
|
|
void reset_mcu(struct ssp_data *data, int reason)
|
|
{
|
|
if(work_busy(&data->work_reset)) {
|
|
ssp_infof("reset work state : pending or running");
|
|
return;
|
|
}
|
|
|
|
ssp_infof("- reason(%u) pending(%u)", reason, !list_empty(&data->pending_list));
|
|
data->reset_type = reason;
|
|
|
|
data->cnt_ssp_reset[RESET_TYPE_MAX]++;
|
|
if(data->reset_type < RESET_TYPE_MAX)
|
|
data->cnt_ssp_reset[data->reset_type]++;
|
|
|
|
ssp_lock_wait_event(&data->reset_lock);
|
|
queue_work(data->debug_wq, &data->work_reset);
|
|
return;
|
|
}
|
|
|
|
void reset_task(struct work_struct *work)
|
|
{
|
|
struct ssp_data *data = container_of((struct work_struct *)work,
|
|
struct ssp_data, work_reset);
|
|
int ret;
|
|
ssp_infof("");
|
|
disable_timestamp_sync_timer(data);
|
|
ret = sensorhub_reset(data);
|
|
if(ret < 0) {
|
|
ssp_errf("reset failed");
|
|
ssp_wake_up_wait_event(&data->reset_lock);
|
|
}
|
|
}
|
|
|
|
static void check_no_event(struct ssp_data *data)
|
|
{
|
|
u64 timestamp = get_current_timestamp();
|
|
int check_sensors[] = {SENSOR_TYPE_ACCELEROMETER, SENSOR_TYPE_GEOMAGNETIC_FIELD,
|
|
SENSOR_TYPE_GYROSCOPE, SENSOR_TYPE_PRESSURE, SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
|
|
SENSOR_TYPE_GAME_ROTATION_VECTOR, SENSOR_TYPE_GYROSCOPE_UNCALIBRATED};
|
|
|
|
int len = sizeof(check_sensors) / sizeof(check_sensors[0]);
|
|
int i, sensor, ret;
|
|
char buffer[9] = {0,};
|
|
bool check_reset = false;
|
|
|
|
if(data->check_noevent_reset_cnt >= 0 && data->check_noevent_reset_cnt == data->cnt_reset)
|
|
check_reset = true;
|
|
|
|
data->check_noevent_reset_cnt = -1;
|
|
|
|
for (i = 0 ; i < len ; i++) {
|
|
sensor = check_sensors[i];
|
|
/* The sensor is registered
|
|
And none batching mode
|
|
And there is no sensor event over 5sec */
|
|
if (data->en_info[sensor].enabled
|
|
&& data->delay[sensor].max_report_latency == 0
|
|
&& data->latest_timestamp[sensor] + 5000000000ULL < timestamp) {
|
|
|
|
if(check_reset) {
|
|
data->check_noevent_reset_cnt = -1;
|
|
reset_mcu(data, RESET_TYPE_KERNEL_NO_EVENT);
|
|
break;
|
|
}
|
|
data->check_noevent_reset_cnt = data->cnt_reset;
|
|
|
|
ssp_infof("sensor(%d) last = %lld, cur = %lld", sensor, data->latest_timestamp[sensor], timestamp);
|
|
|
|
buffer[0] = sensor;
|
|
memcpy(&buffer[1], &(data->delay[sensor]), sizeof(data->delay[sensor]));
|
|
ret = ssp_send_command(data, CMD_SETVALUE, TYPE_MCU, NO_EVENT_CHECK, 0, buffer, sizeof(buffer), NULL, NULL);
|
|
if(ret < 0)
|
|
ssp_errf("type %d no event comm failed ret %d", sensor, ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void print_sensordata(struct ssp_data *data, unsigned int sensor_type)
|
|
{
|
|
if(sensor_type < SENSOR_TYPE_MAX)
|
|
{
|
|
switch (sensor_type) {
|
|
case SENSOR_TYPE_ACCELEROMETER:
|
|
case SENSOR_TYPE_GYROSCOPE:
|
|
case SENSOR_TYPE_INTERRUPT_GYRO:
|
|
ssp_info("%s(%u) : %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].x, data->buf[sensor_type].y,
|
|
data->buf[sensor_type].z,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_GEOMAGNETIC_FIELD:
|
|
ssp_info("%s(%u) : %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].cal_x, data->buf[sensor_type].cal_y,
|
|
data->buf[sensor_type].cal_z, data->buf[sensor_type].accuracy,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
|
|
case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
|
|
ssp_info("%s(%u) : %d, %d, %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].uncal_x,
|
|
data->buf[sensor_type].uncal_y,
|
|
data->buf[sensor_type].uncal_z,
|
|
data->buf[sensor_type].offset_x,
|
|
data->buf[sensor_type].offset_y,
|
|
data->buf[sensor_type].offset_z,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_PRESSURE:
|
|
ssp_info("%s(%u) : %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].pressure,
|
|
data->buf[sensor_type].temperature,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_LIGHT:
|
|
ssp_info("%s(%u) : %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].lux,
|
|
data->buf[sensor_type].cct,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_LIGHT_CCT:
|
|
ssp_info("%s(%u) : %u, %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].lux,
|
|
data->buf[sensor_type].cct,
|
|
data->buf[sensor_type].raw_lux,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_PROXIMITY:
|
|
ssp_info("%s(%u) : %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].prox, data->buf[sensor_type].prox_ex,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_STEP_DETECTOR:
|
|
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].step_det,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_GAME_ROTATION_VECTOR:
|
|
case SENSOR_TYPE_ROTATION_VECTOR:
|
|
ssp_info("%s(%u) : %d, %d, %d, %d, %d (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].quat_a, data->buf[sensor_type].quat_b,
|
|
data->buf[sensor_type].quat_c, data->buf[sensor_type].quat_d,
|
|
data->buf[sensor_type].acc_rot,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_SIGNIFICANT_MOTION:
|
|
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].sig_motion,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_STEP_COUNTER:
|
|
ssp_info("%s(%u) : %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].step_diff,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
case SENSOR_TYPE_LIGHT_AUTOBRIGHTNESS:
|
|
ssp_info("%s(%u) : %u, %u, %u (%lld) (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->buf[sensor_type].ab_lux,
|
|
data->buf[sensor_type].ab_min_flag,
|
|
data->buf[sensor_type].ab_brightness,
|
|
data->buf[sensor_type].timestamp,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
break;
|
|
default:
|
|
ssp_info("%s(%u) : (%ums, %dms)", data->info[sensor_type].name, sensor_type,
|
|
data->delay[sensor_type].sampling_period,
|
|
data->delay[sensor_type].max_report_latency);
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
char name[SENSOR_NAME_MAX_LEN] = "";
|
|
get_ss_sensor_name(data, sensor_type, name, SENSOR_NAME_MAX_LEN);
|
|
ssp_info("%s(%u)", name, sensor_type);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void debug_work_func(struct work_struct *work)
|
|
{
|
|
struct ssp_data *data = container_of(work, struct ssp_data, work_debug);
|
|
unsigned int type;
|
|
|
|
ssp_infof("FW(%d):%u, Sensor state: 0x%llx, En: 0x%llx, Reset cnt: %d[%d : C %u(%u, %u), N %u, %u]",
|
|
data->fw_type, data->curr_fw_rev,
|
|
data->sensor_probe_state, data->sensor_en_state,
|
|
data->cnt_reset, data->cnt_ssp_reset[RESET_TYPE_MAX],
|
|
data->cnt_ssp_reset[RESET_TYPE_KERNEL_COM_FAIL], data->cnt_com_fail, data->cnt_timeout,
|
|
data->cnt_ssp_reset[RESET_TYPE_KERNEL_NO_EVENT], data->cnt_ssp_reset[RESET_TYPE_HUB_NO_EVENT]);
|
|
|
|
for (type = 0; type < SS_SENSOR_TYPE_MAX; type++)
|
|
if(data->en_info[type].enabled) {
|
|
print_sensordata(data, type);
|
|
}
|
|
|
|
if(is_sensorhub_working(data))
|
|
check_no_event(data);
|
|
|
|
}
|
|
|
|
static void debug_timer_func(unsigned long ptr)
|
|
{
|
|
struct ssp_data *data = (struct ssp_data *)ptr;
|
|
|
|
queue_work(data->debug_wq, &data->work_debug);
|
|
mod_timer(&data->debug_timer,
|
|
round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC));
|
|
}
|
|
|
|
void enable_debug_timer(struct ssp_data *data)
|
|
{
|
|
mod_timer(&data->debug_timer,
|
|
round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC));
|
|
}
|
|
|
|
void disable_debug_timer(struct ssp_data *data)
|
|
{
|
|
del_timer_sync(&data->debug_timer);
|
|
cancel_work_sync(&data->work_debug);
|
|
}
|
|
|
|
int initialize_debug_timer(struct ssp_data *data)
|
|
{
|
|
setup_timer(&data->debug_timer, debug_timer_func, (unsigned long)data);
|
|
|
|
data->debug_wq = create_singlethread_workqueue("ssp_debug_wq");
|
|
if (!data->debug_wq) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
INIT_WORK(&data->work_debug, debug_work_func);
|
|
return 0;
|
|
}
|
|
|
|
int print_mcu_debug(char *dataframe, int *index, int dataframe_length)
|
|
{
|
|
u16 length = 0;
|
|
int cur = *index;
|
|
|
|
memcpy(&length, dataframe + *index, 1);
|
|
*index += 1;
|
|
|
|
if (length > dataframe_length - *index || length <= 0) {
|
|
ssp_infof("[M] invalid debug length(%u/%d/%d)",
|
|
length, dataframe_length, cur);
|
|
return length ? length : -1;
|
|
}
|
|
|
|
ssp_info("[M] %s", &dataframe[*index]);
|
|
*index += length;
|
|
return 0;
|
|
}
|
|
|
|
#define SSP_LOG_MAX_BYTE 200
|
|
void print_dataframe(struct ssp_data *data, char *dataframe, int frame_len)
|
|
{
|
|
char raw_data[SSP_LOG_MAX_BYTE*4];
|
|
int i = 0, cur = 0;
|
|
|
|
while ((frame_len - cur) > 0) {
|
|
int size = 0;
|
|
int pr_size = ((frame_len - cur) > SSP_LOG_MAX_BYTE) ? SSP_LOG_MAX_BYTE : (frame_len - cur);
|
|
|
|
memset(raw_data, 0, sizeof(raw_data));
|
|
for (i = 0; i < pr_size; i++)
|
|
size += snprintf(raw_data + size, PAGE_SIZE, "%d ", *(dataframe + cur++));
|
|
|
|
ssp_info("%s", raw_data);
|
|
}
|
|
}
|