/* * 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 #include #include #include #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); } }