432 lines
15 KiB
C
Executable File
432 lines
15 KiB
C
Executable File
/*
|
|
* Copyright (C) 2012, 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 "ssp.h"
|
|
#include <linux/math64.h>
|
|
#include <linux/sched.h>
|
|
|
|
/* SSP -> AP Instruction */
|
|
#define MSG2AP_INST_BYPASS_DATA 0x37
|
|
#define MSG2AP_INST_LIBRARY_DATA 0x01
|
|
#define MSG2AP_INST_DEBUG_DATA 0x03
|
|
#define MSG2AP_INST_BIG_DATA 0x04
|
|
#define MSG2AP_INST_META_DATA 0x05
|
|
#define MSG2AP_INST_TIME_SYNC 0x06
|
|
#define MSG2AP_INST_RESET 0x07
|
|
|
|
/*************************************************************************/
|
|
/* SSP parsing the dataframe */
|
|
/*************************************************************************/
|
|
|
|
static void generate_data(struct ssp_data *data, struct sensor_value *sensorsdata,
|
|
int iSensorData, u64 timestamp)
|
|
{
|
|
u64 move_timestamp = data->lastTimestamp[iSensorData];
|
|
if ((iSensorData != PROXIMITY_SENSOR) && (iSensorData != GESTURE_SENSOR)
|
|
&& (iSensorData != STEP_DETECTOR) && (iSensorData != SIG_MOTION_SENSOR)
|
|
&& (iSensorData != STEP_COUNTER)) {
|
|
while ((move_timestamp * 10 + data->adDelayBuf[iSensorData] * 15) < (timestamp * 10)) {
|
|
move_timestamp += data->adDelayBuf[iSensorData];
|
|
sensorsdata->timestamp = move_timestamp;
|
|
data->report_sensor_data[iSensorData](data, sensorsdata);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void get_timestamp(struct ssp_data *data, char *pchRcvDataFrame,
|
|
int *iDataIdx, struct sensor_value *sensorsdata,
|
|
struct ssp_time_diff *sensortime, int iSensorData)
|
|
{
|
|
if (sensortime->batch_mode == BATCH_MODE_RUN) {
|
|
if (sensortime->batch_count == sensortime->batch_count_fixed) {
|
|
if (sensortime->time_diff == data->adDelayBuf[iSensorData]) {
|
|
generate_data(data, sensorsdata, iSensorData,
|
|
(data->timestamp - data->adDelayBuf[iSensorData] * (sensortime->batch_count_fixed - 1)));
|
|
}
|
|
sensorsdata->timestamp = data->timestamp - ((sensortime->batch_count - 1) * sensortime->time_diff);
|
|
} else {
|
|
if (sensortime->batch_count > 1)
|
|
sensorsdata->timestamp = data->timestamp - ((sensortime->batch_count - 1) * sensortime->time_diff);
|
|
else
|
|
sensorsdata->timestamp = data->timestamp;
|
|
}
|
|
} else {
|
|
if (((sensortime->irq_diff * 10) > (data->adDelayBuf[iSensorData] * 18))
|
|
&& ((sensortime->irq_diff * 10) < (data->adDelayBuf[iSensorData] * 100))) {
|
|
generate_data(data, sensorsdata, iSensorData, data->timestamp);
|
|
}
|
|
sensorsdata->timestamp = data->timestamp;
|
|
}
|
|
*iDataIdx += 4;
|
|
}
|
|
|
|
static void get_3axis_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 6);
|
|
*iDataIdx += 6;
|
|
}
|
|
|
|
static void get_uncalib_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 12);
|
|
*iDataIdx += 12;
|
|
}
|
|
|
|
static void get_geomagnetic_uncaldata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 12);
|
|
*iDataIdx += 12;
|
|
}
|
|
|
|
static void get_geomagnetic_rawdata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 6);
|
|
*iDataIdx += 6;
|
|
}
|
|
|
|
static void get_geomagnetic_caldata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
#ifdef SAVE_MAG_LOG
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 20);
|
|
*iDataIdx += 20;
|
|
#else
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 7);
|
|
*iDataIdx += 7;
|
|
#endif
|
|
}
|
|
|
|
static void get_rot_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 17);
|
|
*iDataIdx += 17;
|
|
}
|
|
|
|
static void get_step_det_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 1);
|
|
*iDataIdx += 1;
|
|
}
|
|
|
|
static void get_light_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
#if defined(CONFIG_SENSORS_SSP_TMG399X)
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 10);
|
|
*iDataIdx += 10;
|
|
#elif defined(CONFIG_SENSORS_SSP_MAX88921)
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 12);
|
|
*iDataIdx += 12;
|
|
#else
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 8);
|
|
*iDataIdx += 8;
|
|
#endif
|
|
}
|
|
|
|
static void get_pressure_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
s16 temperature = 0;
|
|
memcpy(&sensorsdata->pressure[0], pchRcvDataFrame + *iDataIdx, 4);
|
|
memcpy(&temperature, pchRcvDataFrame + *iDataIdx + 4, 2);
|
|
sensorsdata->pressure[1] = temperature;
|
|
*iDataIdx += 6;
|
|
}
|
|
|
|
static void get_gesture_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
#if defined(CONFIG_SENSORS_SSP_MAX88921)
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 38);
|
|
*iDataIdx += 38;
|
|
#else//CONFIG_SENSORS_SSP_TMG399X
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 20);
|
|
*iDataIdx += 20;
|
|
#endif
|
|
}
|
|
|
|
static void get_proximity_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
#if defined(CONFIG_SENSORS_SSP_MAX88921)
|
|
memset(&sensorsdata->prox[0], 0, 2);
|
|
memcpy(&sensorsdata->prox[0], pchRcvDataFrame + *iDataIdx, 1);
|
|
memcpy(&sensorsdata->prox[1], pchRcvDataFrame + *iDataIdx + 1, 2);
|
|
*iDataIdx += 3;
|
|
#else
|
|
memset(&sensorsdata->prox[0], 0, 1);
|
|
memcpy(&sensorsdata->prox[0], pchRcvDataFrame + *iDataIdx, 2);
|
|
//memcpy(&sensorsdata->prox[1], pchRcvDataFrame + *iDataIdx + 1, 1);
|
|
*iDataIdx += 2;
|
|
#endif
|
|
}
|
|
|
|
static void get_proximity_rawdata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
#if defined(CONFIG_SENSORS_SSP_MAX88921)
|
|
memcpy(&sensorsdata->prox[0], pchRcvDataFrame + *iDataIdx, 2);
|
|
*iDataIdx += 2;
|
|
#else
|
|
memcpy(&sensorsdata->prox[0], pchRcvDataFrame + *iDataIdx, 1);
|
|
*iDataIdx += 1;
|
|
#endif
|
|
}
|
|
|
|
static void get_temp_humidity_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memset(&sensorsdata->data[2], 0, 2);
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 5);
|
|
*iDataIdx += 5;
|
|
}
|
|
|
|
static void get_sig_motion_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 1);
|
|
*iDataIdx += 1;
|
|
}
|
|
|
|
static void get_step_cnt_sensordata(char *pchRcvDataFrame, int *iDataIdx,
|
|
struct sensor_value *sensorsdata)
|
|
{
|
|
memcpy(&sensorsdata->step_diff, pchRcvDataFrame + *iDataIdx, 4);
|
|
*iDataIdx += 4;
|
|
}
|
|
|
|
int handle_big_data(struct ssp_data *data, char *pchRcvDataFrame, int *pDataIdx) {
|
|
u8 bigType = 0;
|
|
struct ssp_big *big = kzalloc(sizeof(*big), GFP_KERNEL);
|
|
big->data = data;
|
|
bigType = pchRcvDataFrame[(*pDataIdx)++];
|
|
memcpy(&big->length, pchRcvDataFrame + *pDataIdx, 4);
|
|
*pDataIdx += 4;
|
|
memcpy(&big->addr, pchRcvDataFrame + *pDataIdx, 4);
|
|
*pDataIdx += 4;
|
|
|
|
if (bigType >= BIG_TYPE_MAX) {
|
|
kfree(big);
|
|
return FAIL;
|
|
}
|
|
|
|
INIT_WORK(&big->work, data->ssp_big_task[bigType]);
|
|
queue_work(data->debug_wq, &big->work);
|
|
return SUCCESS;
|
|
}
|
|
|
|
void refresh_task(struct work_struct *work) {
|
|
struct ssp_data *data = container_of((struct delayed_work *)work,
|
|
struct ssp_data, work_refresh);
|
|
|
|
if(data->bSspShutdown == true) {
|
|
pr_err("[SSP]: %s - ssp already shutdown\n", __func__);
|
|
return;
|
|
}
|
|
|
|
wake_lock(&data->ssp_wake_lock);
|
|
pr_err("[SSP]: %s\n", __func__);
|
|
data->uResetCnt++;
|
|
|
|
if (initialize_mcu(data) > 0) {
|
|
sync_sensor_state(data);
|
|
ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET);
|
|
if (data->uLastAPState != 0)
|
|
ssp_send_cmd(data, data->uLastAPState, 0);
|
|
if (data->uLastResumeState != 0)
|
|
ssp_send_cmd(data, data->uLastResumeState, 0);
|
|
data->uTimeOutCnt = 0;
|
|
}
|
|
|
|
wake_unlock(&data->ssp_wake_lock);
|
|
}
|
|
|
|
int queue_refresh_task(struct ssp_data *data, int delay) {
|
|
cancel_delayed_work_sync(&data->work_refresh);
|
|
|
|
INIT_DELAYED_WORK(&data->work_refresh, refresh_task);
|
|
queue_delayed_work(data->debug_wq, &data->work_refresh,
|
|
msecs_to_jiffies(delay));
|
|
return SUCCESS;
|
|
}
|
|
|
|
int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) {
|
|
int iDataIdx, iSensorData;
|
|
u16 length = 0;
|
|
struct sensor_value sensorsdata;
|
|
struct ssp_time_diff sensortime;
|
|
|
|
for (iDataIdx = 0; iDataIdx < iLength;) {
|
|
switch (pchRcvDataFrame[iDataIdx++]) {
|
|
case MSG2AP_INST_BYPASS_DATA:
|
|
iSensorData = pchRcvDataFrame[iDataIdx++];
|
|
if ((iSensorData < 0) || (iSensorData >= SENSOR_MAX)) {
|
|
pr_err("[SSP]: %s - Mcu data frame1 error %d\n", __func__,
|
|
iSensorData);
|
|
return ERROR;
|
|
}
|
|
memcpy(&length, pchRcvDataFrame + iDataIdx, 2);
|
|
iDataIdx += 2;
|
|
sensortime.batch_count = sensortime.batch_count_fixed = length;
|
|
sensortime.batch_mode = length > 1 ? BATCH_MODE_RUN : BATCH_MODE_NONE;
|
|
sensortime.irq_diff = data->timestamp - data->lastTimestamp[iSensorData];
|
|
|
|
if (sensortime.batch_mode == BATCH_MODE_RUN) {
|
|
if (data->reportedData[iSensorData] == true) {
|
|
u64 time;
|
|
sensortime.time_diff = div64_long((s64)(data->timestamp - data->lastTimestamp[iSensorData]), (s64)length);
|
|
if (length > 8)
|
|
time = data->adDelayBuf[iSensorData] * 18;
|
|
else if (length > 4)
|
|
time = data->adDelayBuf[iSensorData] * 25;
|
|
else if (length > 2)
|
|
time = data->adDelayBuf[iSensorData] * 50;
|
|
else
|
|
time = data->adDelayBuf[iSensorData] * 100;
|
|
if ((sensortime.time_diff * 10) > time) {
|
|
data->lastTimestamp[iSensorData] = data->timestamp - (data->adDelayBuf[iSensorData] * length);
|
|
sensortime.time_diff = data->adDelayBuf[iSensorData];
|
|
} else {
|
|
time = data->adDelayBuf[iSensorData] * 18;
|
|
if ((sensortime.time_diff * 10) > time)
|
|
sensortime.time_diff = data->adDelayBuf[iSensorData];
|
|
}
|
|
} else {
|
|
if (data->lastTimestamp[iSensorData] < (data->timestamp - (data->adDelayBuf[iSensorData] * length))) {
|
|
data->lastTimestamp[iSensorData] = data->timestamp - (data->adDelayBuf[iSensorData] * length);
|
|
sensortime.time_diff = data->adDelayBuf[iSensorData];
|
|
} else
|
|
sensortime.time_diff = div64_long((s64)(data->timestamp - data->lastTimestamp[iSensorData]), (s64)length);
|
|
}
|
|
} else {
|
|
if (data->reportedData[iSensorData] == false)
|
|
sensortime.irq_diff = data->adDelayBuf[iSensorData];
|
|
}
|
|
|
|
do {
|
|
data->get_sensor_data[iSensorData](pchRcvDataFrame, &iDataIdx,
|
|
&sensorsdata);
|
|
|
|
get_timestamp(data, pchRcvDataFrame, &iDataIdx, &sensorsdata, &sensortime, iSensorData);
|
|
if (sensortime.irq_diff > 1000000)
|
|
data->report_sensor_data[iSensorData](data, &sensorsdata);
|
|
else if ((iSensorData == PROXIMITY_SENSOR) || (iSensorData == PROXIMITY_RAW)
|
|
|| (iSensorData == GESTURE_SENSOR) || (iSensorData == SIG_MOTION_SENSOR))
|
|
data->report_sensor_data[iSensorData](data, &sensorsdata);
|
|
else
|
|
pr_err("[SSP]: %s irq_diff is under 1msec (%d)\n", __func__, iSensorData);
|
|
sensortime.batch_count--;
|
|
} while ((sensortime.batch_count > 0) && (iDataIdx < iLength));
|
|
|
|
if (sensortime.batch_count > 0)
|
|
pr_err("[SSP]: %s batch count error (%d)\n", __func__, sensortime.batch_count);
|
|
|
|
data->lastTimestamp[iSensorData] = data->timestamp;
|
|
data->reportedData[iSensorData] = true;
|
|
break;
|
|
case MSG2AP_INST_DEBUG_DATA:
|
|
iSensorData = print_mcu_debug(pchRcvDataFrame, &iDataIdx, iLength);
|
|
if (iSensorData) {
|
|
pr_err("[SSP]: %s - Mcu data frame3 error %d\n", __func__,
|
|
iSensorData);
|
|
return ERROR;
|
|
}
|
|
break;
|
|
case MSG2AP_INST_LIBRARY_DATA:
|
|
memcpy(&length, pchRcvDataFrame + iDataIdx, 2);
|
|
iDataIdx += 2;
|
|
ssp_sensorhub_handle_data(data, pchRcvDataFrame, iDataIdx,
|
|
iDataIdx + length);
|
|
iDataIdx += length;
|
|
break;
|
|
case MSG2AP_INST_BIG_DATA:
|
|
handle_big_data(data, pchRcvDataFrame, &iDataIdx);
|
|
break;
|
|
case MSG2AP_INST_META_DATA:
|
|
sensorsdata.meta_data.what = pchRcvDataFrame[iDataIdx++];
|
|
sensorsdata.meta_data.sensor = pchRcvDataFrame[iDataIdx++];
|
|
report_meta_data(data, &sensorsdata);
|
|
break;
|
|
case MSG2AP_INST_TIME_SYNC:
|
|
data->bTimeSyncing = true;
|
|
break;
|
|
case MSG2AP_INST_RESET:
|
|
queue_refresh_task(data, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
void initialize_function_pointer(struct ssp_data *data)
|
|
{
|
|
data->get_sensor_data[ACCELEROMETER_SENSOR] = get_3axis_sensordata;
|
|
data->get_sensor_data[GYROSCOPE_SENSOR] = get_3axis_sensordata;
|
|
data->get_sensor_data[GEOMAGNETIC_UNCALIB_SENSOR] =
|
|
get_geomagnetic_uncaldata;
|
|
data->get_sensor_data[GEOMAGNETIC_RAW] = get_geomagnetic_rawdata;
|
|
data->get_sensor_data[GEOMAGNETIC_SENSOR] =
|
|
get_geomagnetic_caldata;
|
|
data->get_sensor_data[PRESSURE_SENSOR] = get_pressure_sensordata;
|
|
data->get_sensor_data[GESTURE_SENSOR] = get_gesture_sensordata;
|
|
data->get_sensor_data[PROXIMITY_SENSOR] = get_proximity_sensordata;
|
|
data->get_sensor_data[PROXIMITY_RAW] = get_proximity_rawdata;
|
|
data->get_sensor_data[LIGHT_SENSOR] = get_light_sensordata;
|
|
data->get_sensor_data[TEMPERATURE_HUMIDITY_SENSOR] =
|
|
get_temp_humidity_sensordata;
|
|
data->get_sensor_data[ROTATION_VECTOR] = get_rot_sensordata;
|
|
data->get_sensor_data[GAME_ROTATION_VECTOR] = get_rot_sensordata;
|
|
data->get_sensor_data[STEP_DETECTOR] = get_step_det_sensordata;
|
|
data->get_sensor_data[SIG_MOTION_SENSOR] = get_sig_motion_sensordata;
|
|
data->get_sensor_data[GYRO_UNCALIB_SENSOR] = get_uncalib_sensordata;
|
|
data->get_sensor_data[STEP_COUNTER] = get_step_cnt_sensordata;
|
|
|
|
data->report_sensor_data[ACCELEROMETER_SENSOR] = report_acc_data;
|
|
data->report_sensor_data[GYROSCOPE_SENSOR] = report_gyro_data;
|
|
data->report_sensor_data[GEOMAGNETIC_UNCALIB_SENSOR] =
|
|
report_mag_uncaldata;
|
|
data->report_sensor_data[GEOMAGNETIC_RAW] = report_geomagnetic_raw_data;
|
|
data->report_sensor_data[GEOMAGNETIC_SENSOR] =
|
|
report_mag_data;
|
|
data->report_sensor_data[PRESSURE_SENSOR] = report_pressure_data;
|
|
data->report_sensor_data[GESTURE_SENSOR] = report_gesture_data;
|
|
data->report_sensor_data[PROXIMITY_SENSOR] = report_prox_data;
|
|
data->report_sensor_data[PROXIMITY_RAW] = report_prox_raw_data;
|
|
data->report_sensor_data[LIGHT_SENSOR] = report_light_data;
|
|
data->report_sensor_data[TEMPERATURE_HUMIDITY_SENSOR] =
|
|
report_temp_humidity_data;
|
|
data->report_sensor_data[ROTATION_VECTOR] = report_rot_data;
|
|
data->report_sensor_data[GAME_ROTATION_VECTOR] = report_game_rot_data;
|
|
data->report_sensor_data[STEP_DETECTOR] = report_step_det_data;
|
|
data->report_sensor_data[SIG_MOTION_SENSOR] = report_sig_motion_data;
|
|
data->report_sensor_data[GYRO_UNCALIB_SENSOR] = report_uncalib_gyro_data;
|
|
data->report_sensor_data[STEP_COUNTER] = report_step_cnt_data;
|
|
|
|
data->ssp_big_task[BIG_TYPE_DUMP] = ssp_dump_task;
|
|
data->ssp_big_task[BIG_TYPE_READ_LIB] = ssp_read_big_library_task;
|
|
data->ssp_big_task[BIG_TYPE_VOICE_NET] = ssp_send_big_library_task;
|
|
data->ssp_big_task[BIG_TYPE_VOICE_GRAM] = ssp_send_big_library_task;
|
|
data->ssp_big_task[BIG_TYPE_VOICE_PCM] = ssp_pcm_dump_task;
|
|
#ifdef CONFIG_SENSORS_SSP_SHTC1
|
|
data->ssp_big_task[BIG_TYPE_TEMP] = ssp_temp_task;
|
|
#endif
|
|
}
|