Files

1652 lines
40 KiB
C
Executable File

#if TSP_PATCH
/*
Header
*/
#define MXT_PATCH_LOCK_CHECK 1
#define MXT_PATCH_SUPP_CHECK 1
#define MXT_PATCH_STAGE_RESET 1
#define TIME_WRAP_AROUND(x, y) (((y)>(x)) ? (y)-(x) : (0-(x))+(y))
#define MXT_PATCH_MAGIC 0x52296416
#define MXT_PATCH_VERSION 1
#define MXT_PATCH_MAX_STAGE 255
#define MXT_PATCH_MAX_TLINE 255
#define MXT_PATCH_MAX_TRIG 255
#define MXT_PATCH_MAX_ITEM 255
#define MXT_PATCH_MAX_TYPE 255
#define MXT_PATCH_MAX_CON 255
#define MXT_PATCH_MAX_EVENT 255
#define MXT_PATCH_MAX_MSG_SIZE 10
#define MXT_XML_CON_NONE "0" //0
#define MXT_XML_CON_EQUAL "=" //1
#define MXT_XML_CON_BELOW "<" //2
#define MXT_XML_CON_ABOVE ">" //3
#define MXT_XML_CON_PLUS "+" //4
#define MXT_XML_CON_MINUS "-" //5
#define MXT_XML_CON_MUL "*" //6
#define MXT_XML_CON_DIV "/" //7
#define MXT_XML_CON_MASK "&" //8
#define MXT_XML_SRC_NONE "0" //0
#define MXT_XML_SRC_CHRG "TA" //1
#define MXT_XML_SRC_FCNT "FCNT" //2
#define MXT_XML_SRC_AREA "AREA" //3
#define MXT_XML_SRC_AMP "AMP" //4
#define MXT_XML_SRC_SUM "SUM" //5
#define MXT_XML_SRC_TCH "TCH" //6
#define MXT_XML_SRC_ATCH "ATCH" //7
#define MXT_XML_SRC_KCNT "KCNT" //8
#define MXT_XML_SRC_KVAL "KVAL" //9
#define MXT_XML_ACT_NONE "0" //0
#define MXT_XML_ACT_CAL "CAL" //1
#define MXT_XML_ACT_EXTMR "EXTMR" //2
enum{
MXT_PATCH_CON_NONE = 0,
MXT_PATCH_CON_EQUAL, //1
MXT_PATCH_CON_BELOW, //2
MXT_PATCH_CON_ABOVE, //3
MXT_PATCH_CON_PLUS, //4
MXT_PATCH_CON_MINUS, //5
MXT_PATCH_CON_MUL, //6
MXT_PATCH_CON_DIV, //7
MXT_PATCH_CON_MASK, //8
//...
MXT_PATCH_CON_END
};
enum {
MXT_PATCH_ITEM_NONE = 0,
MXT_PATCH_ITEM_CHARG, //1
MXT_PATCH_ITEM_FCNT, //2
MXT_PATCH_ITEM_AREA, //3
MXT_PATCH_ITEM_AMP, //4
MXT_PATCH_ITEM_SUM, //5
MXT_PATCH_ITEM_TCH, //6
MXT_PATCH_ITEM_ATCH, //7
MXT_PATCH_ITEM_KCNT, //8
MXT_PATCH_ITEM_KVAL, //9
//...
MXT_PATCH_ITEM_END
};
enum {
MXT_PATCH_ACTION_NONE = 0,
MXT_PATCH_ACTION_CAL,
MXT_PATCH_ACTION_EXTEND_TIMER,
MXT_PATCH_ACTION_GOTO_STAGE,
//...
MXT_PATCH_ACTION_END
};
struct patch_header{ // 32b
u32 magic;
u32 size;
u32 date;
u16 version;
u8 option;
u8 debug;
u8 timer_id;
u8 stage_cnt;
u8 trigger_cnt;
u8 event_cnt;
u8 reserved[12];
};
struct stage_def{ // 8b
u8 stage_id;
u8 option;
u16 stage_period;
u8 cfg_cnt;
u8 test_cnt;
#if MXT_PATCH_STAGE_RESET
u16 reset_period;
#endif
};
struct stage_cfg{ // 4b
u8 obj_type;
u8 option;
u8 offset;
u8 val;
};
struct test_line{ // 12b
u8 test_id;
u8 item_cnt;
u8 cfg_cnt;
u8 act_id;
u16 act_val;
u16 option;
u16 check_cnt;
u8 reserved[2];
};
struct action_cfg{ // 4b
u8 obj_type;
u8 option;
u8 offset;
u8 val;
};
struct item_val{ // 4b
u8 val_id;
u8 val_eq;
u16 val;
};
struct test_item{ // 8b
u8 src_id;
u8 cond;
u8 reserved[2];
struct item_val ival;
};
// Message Trigger
struct trigger{ // 12b
u8 tid;
u8 option;
u8 object;
u8 index;
u8 match_cnt;
u8 cfg_cnt;
u8 reserved[3];
u8 act_id;
u16 act_val;
};
struct match{ //8b
u8 offset;
u8 cond;
u16 mask;
u8 reserved[2];
u16 val;
};
struct trigger_cfg{ // 4b
u8 obj_type;
u8 reserved;
u8 offset;
u8 val;
};
// Event
struct user_event{ // 8b
u8 eid;
u8 option;
u8 cfg_cnt;
u8 reserved[5];
};
struct event_cfg{ // 4b
u8 obj_type;
u8 reserved;
u8 offset;
u8 val;
};
/*
Source
*/
struct test_src{
int charger;
int finger_cnt;
int area;
int amp;
int sum_size;
int tch_ch;
int atch_ch;
int key_cnt;
int key_val;
};
#if MXT_PATCH_LOCK_CHECK
struct touch_pos{
u8 tcount[MXT_MAX_FINGER];
u16 initx[MXT_MAX_FINGER];
u16 inity[MXT_MAX_FINGER];
u16 oldx[MXT_MAX_FINGER];
u16 oldy[MXT_MAX_FINGER];
u8 locked_id;
u8 moved_cnt;
u8 option;
u8 cal_enable;
u8 reset_cnt;
u8 distance;
u8 maxdiff;
u8 locked_cnt;
u8 jitter;
};
#endif
#ifndef __mxt_patch_debug
#define __mxt_patch_debug(_data, ...) if(data->patch.debug) \
dev_info(&(_data)->client->dev, __VA_ARGS__);
#endif
#ifndef __mxt_patch_ddebug
#define __mxt_patch_ddebug(_data, ...) if(data->patch.debug>1) \
dev_info(&(_data)->client->dev, __VA_ARGS__);
#endif
/* Function Define */
static void mxt_patch_dump_source(struct mxt_data *data,
bool do_action);
static int mxt_patch_run_stage(struct mxt_data *data);
/* Porting */
static void mxt_patch_calibration(struct mxt_data *data)
{
mxt_write_object(data, MXT_GEN_COMMANDPROCESSOR_T6,
MXT_COMMAND_CALIBRATE, 1);
}
static int mxt_patch_start_timer(struct mxt_data *data, u16 period)
{
struct mxt_object* object;
int ret = 0;
u8 t61_reg[5] = {3, 1, 0, 0, 0};
object = mxt_get_object(data, MXT_SPT_TIMER_T61);
t61_reg[3] = period & 0xFF;
t61_reg[4] = (period >> 8) & 0xFF;
ret = mxt_write_mem(data, object->start_address+
5*data->patch.timer_id, 5, t61_reg);
if (!ret) {
__mxt_patch_debug(data, "START STAGE: %d TIMER[%d] %dms\n",
data->patch.cur_stage, data->patch.timer_id, period);
}
return ret;
}
static int mxt_patch_stop_timer(struct mxt_data *data)
{
struct mxt_object* object;
int ret = 0;
u8 t61_reg[5] = {3, 2, 0, 0, 0}; //20120807
object = mxt_get_object(data, MXT_SPT_TIMER_T61);
ret = mxt_write_mem(data, object->start_address+
5*data->patch.timer_id, 5, t61_reg);
if (!ret) {
__mxt_patch_debug(data, "STOP TIMER[%d]\n",
data->patch.timer_id);
}
return ret;
}
/*
OPT= 0:ALL, 2:BATT ONLY, 3:TA ONLY
*/
static int mxt_patch_check_tacfg(struct mxt_data *data,
u8 option, u8 ta_mode)
{
if(option&0x02){
if(ta_mode){//TA
if((option&0x01)==0){
__mxt_patch_ddebug(data, "|- SCFG BATT SKIP");
return 1;
}
}
else{// BATT
if((option&0x01)==1){
__mxt_patch_ddebug(data, "|- SCFG TA SKIP");
return 1;
}
}
}
if(option&0x04){
if(data->setdata){
__mxt_patch_ddebug(data, "|- SCFG RF");
return 0;
}
else{
__mxt_patch_ddebug(data, "|- SCFG RF SKIP");
return 1;
}
}
return 0;
}
static int mxt_patch_write_stage_cfg(struct mxt_data *data,
struct stage_cfg* pscfg, bool do_action)
{
if(do_action){
#if TSP_INFORM_CHARGER
if(mxt_patch_check_tacfg(data, pscfg->option,
data->charging_mode)){
return 0;
}
#endif
__mxt_patch_debug(data, "|- SCFG_WRITE: OBJECT_TYPE:%d"
" OFFSET:%d VAL:%d OPT:%d\n",
pscfg->obj_type, pscfg->offset,
pscfg->val, pscfg->option);
mxt_write_object(data, pscfg->obj_type,
pscfg->offset, pscfg->val);
}
return 0;
}
static int mxt_patch_write_action_cfg(struct mxt_data *data,
struct action_cfg* pacfg, bool do_action)
{
if(do_action){
#if TSP_INFORM_CHARGER
if(mxt_patch_check_tacfg(data, pacfg->option,
data->charging_mode)){
return 0;
}
#endif
__mxt_patch_debug(data, "|-- ACFG_WRITE: OBJECT_TYPE:%d"
" OFFSET:%d VAL:%d OPT:%d\n",
pacfg->obj_type, pacfg->offset,
pacfg->val, pacfg->option);
mxt_write_object(data, pacfg->obj_type,
pacfg->offset, pacfg->val);
}
return 0;
}
static int mxt_patch_write_trigger_cfg(struct mxt_data *data,
struct trigger_cfg* ptcfg, bool do_action)
{
if(do_action){
__mxt_patch_debug(data, "|-- TCFG_WRITE: OBJECT_TYPE:%d"
" OFFSET:%d VAL:%d\n",
ptcfg->obj_type, ptcfg->offset, ptcfg->val);
mxt_write_object(data, ptcfg->obj_type,
ptcfg->offset, ptcfg->val);
}
return 0;
}
static int mxt_patch_write_event_cfg(struct mxt_data *data,
struct event_cfg* pecfg, bool do_action)
{
if(do_action){
__mxt_patch_debug(data, "|-- ECFG_WRITE: OBJECT_TYPE:%d"
" OFFSET:%d VAL:%d\n",
pecfg->obj_type, pecfg->offset, pecfg->val);
mxt_write_object(data, pecfg->obj_type,
pecfg->offset, pecfg->val);
}
return 0;
}
static int mxt_patch_predefined_action(struct mxt_data *data,
u8 action_id, u16 action_val, bool do_action)
{
if(do_action){
switch(action_id){
case MXT_PATCH_ACTION_NONE:
__mxt_patch_debug(data, "|-- ACTION NONE\n");
break;
case MXT_PATCH_ACTION_CAL:
__mxt_patch_debug(data, "|-- ACTION CALIBRATE: %d\n",
action_val);
mxt_patch_calibration(data);
data->patch.start = false; // Wait Restart
data->patch.start_stage = action_val;
break;
case MXT_PATCH_ACTION_EXTEND_TIMER:
__mxt_patch_debug(data, "|-- ACTION EXTEND TIMER: %d\n",
action_val);
mxt_patch_start_timer(data, action_val);
break;
case MXT_PATCH_ACTION_GOTO_STAGE:
__mxt_patch_debug(data, "|-- ACTION GOTO STAGE: %d\n",
action_val);
data->patch.skip_test = 1;
data->patch.cur_stage = action_val;
data->patch.run_stage = false;
break;
default:
__mxt_patch_debug(data, "@@ INVALID ACTION ID=%d !!\n",
action_id);
return -1;
}
}
return 0;
}
#if MXT_PATCH_LOCK_CHECK
#define MXT_PATCH_T71_PTN_OPT 1
#define MXT_PATCH_T71_PTN_CAL 2
struct touch_pos tpos_data;
static void mxt_patch_init_tpos(struct mxt_data *data,
struct touch_pos* tpos)
{
int i;
for(i=0;i<MXT_MAX_FINGER;i++){
tpos->tcount[i] = 0;
tpos->initx[i] = 0;
tpos->inity[i] = 0;
tpos->oldx[i] = 0;
tpos->oldy[i] = 0;
}
tpos->locked_id = 0xff;
tpos->moved_cnt = 0;
}
static bool mxt_patch_check_locked(struct mxt_data *data,
struct touch_pos* tpos, u8 tid, u16 x, u16 y)
{
s16 diffx, diffy;
u32 distance;
//OLD DIFF
diffx = x - tpos->oldx[tid];
diffy = y - tpos->oldy[tid];
distance = abs(diffx) + abs(diffy);
// INIT DIFF
if((tpos->initx[tid] != 0)&&(tpos->inity[tid] != 0)){
diffx = x - tpos->initx[tid];
diffy = y - tpos->inity[tid];
__mxt_patch_ddebug(data,
"[TPOS] INITDIFF[%d] ABS X=%d, ABS Y=%d\n",
tid, (int)abs(diffx), (int)abs(diffy));
}
if((tpos->initx[tid] == 0)&&(tpos->inity[tid] == 0)){
__mxt_patch_ddebug(data,
"[TPOS] INITSET[%d] X=%d, Y=%d\n", tid, x, y);
tpos->initx[tid] = x;
tpos->inity[tid] = y;
tpos->moved_cnt = 0;
}else{
// OLD DIFF vs INIT DIFF
if((distance < tpos->jitter)&&
((abs(diffx) > tpos->maxdiff)||
(abs(diffy) > tpos->maxdiff))){
tpos->moved_cnt++;
}
}
if(tpos->moved_cnt > tpos->reset_cnt){
__mxt_patch_ddebug(data,
"[TPOS] RESET[%d] X=%d, Y=%d\n", tid, x, y);
tpos->initx[tid] = x;
tpos->inity[tid] = y;
tpos->moved_cnt = 0;
}
//__mxt_patch_ddebug(data, "[TPOS] %d, %d, %d, %d, DISTANCE %d\n",
// x, y, tpos->oldx[tid], tpos->oldy[tid], distance);
if((distance < tpos->distance)&&
(abs(diffx) < tpos->maxdiff)&&
(abs(diffy) < tpos->maxdiff)){
return true;
}
else
return false;
return false;
}
static void mxt_patch_check_pattern(struct mxt_data *data,
struct touch_pos* tpos, u8 tid, u16 x, u16 y, u8 finger_cnt)
{
bool cal_condition=false;
if(!finger_cnt){
return;
}
if(mxt_patch_check_locked(data, tpos, tid, x, y)){
tpos->tcount[tid] = tpos->tcount[tid]+1;
//__mxt_patch_debug(data, "[TPOS] INC TCOUNT[%d]=%d\n",
// tid, tpos->tcount[tid]);
}else{
tpos->tcount[tid] = 0;
//__mxt_patch_debug(data, "[TPOS] CLEAR TCOUNT[%d]=%d\n",
// tid, tpos->tcount[tid]);
}
tpos->oldx[tid] = x;
tpos->oldy[tid] = y;
if(finger_cnt == 1){
if(tpos->tcount[tid] > tpos->locked_cnt){
__mxt_patch_debug(data, "[TPOS] ONE TOUCH LOCKED\n");
mxt_patch_init_tpos(data, tpos);
cal_condition = true;
}
}else{
if((tpos->tcount[tid] > tpos->locked_cnt) &&
tpos->locked_id != tid && tpos->locked_id != 0xff){
__mxt_patch_debug(data, "[TPOS] TWO TOUCH LOCKED [%d, %d]\n",
tid, tpos->locked_id);
mxt_patch_init_tpos(data, tpos);
cal_condition = true;
}
if(tpos->tcount[tid] > tpos->locked_cnt){
//__mxt_patch_debug(data, "[TSP] LOCKED FOUND %d\n",
// tpos->locked_id);
tpos->locked_id = tid;
if(tpos->tcount[tid] > 200){
__mxt_patch_debug(data, "[TPOS] OVER LOCKED\n");
cal_condition = true;
}
}
}
if(cal_condition){
int error = mxt_read_object(data,
MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71,
MXT_PATCH_T71_PTN_CAL, &tpos->cal_enable);
if (error) {
dev_err(&data->client->dev, "%s: Error read T71 [%d]\n",
__func__, error);
} else {
if(tpos->cal_enable){
__mxt_patch_debug(data, "[TPOS] CAL\n");
mxt_patch_calibration(data);
error = mxt_read_object(data,
MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71,
MXT_PATCH_T71_PTN_OPT, &tpos->option);
if(!error){
if(tpos->option&0x01){ // Onetime
mxt_write_object(data,
MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71,
MXT_PATCH_T71_PTN_CAL, 0);
__mxt_patch_debug(data, "[TPOS] DISABLE T71[2]\n");
}
}
}
else{
__mxt_patch_debug(data, "[TPOS] SKIP CAL T71[2]=0\n");
}
}
}
}
#endif
#if MXT_PATCH_SUPP_CHECK
struct touch_supp{
u32 old_time;
u8 repeat_cnt;
u8 time_gap;
u8 repeat_max;
};
struct touch_supp tsupp_data;
static void mxt_patch_init_supp(struct mxt_data *data,
struct touch_supp* tsup)
{
tsup->old_time = jiffies_to_msecs(jiffies);
tsup->repeat_cnt = 0;
}
static void mxt_patch_check_supp(struct mxt_data *data, struct touch_supp* tsup)
{
u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff;
time_diff = TIME_WRAP_AROUND(tsup->old_time, curr_time);
if(time_diff < tsup->time_gap*100){
__mxt_patch_debug(data, "[TSUP] Abnormal suppress %d\n",
tsup->repeat_cnt);
if(tsup->repeat_cnt++ > tsup->repeat_max){
__mxt_patch_debug(data, "[TSUP] Abnormal suppress detected\n");
mxt_patch_calibration(data);
}
}
else{
tsup->repeat_cnt = 0;
__mxt_patch_debug(data, "[TSUP] Normal suppress\n");
}
tsup->old_time = curr_time;
mxt_patch_dump_source(data, true);
}
#endif
#define MXT_PATCH_T71_DATA_MAX 10
static void mxt_patch_load_t71data(struct mxt_data *data)
{
struct mxt_object *obj;
u8 buf[MXT_PATCH_T71_DATA_MAX];
int error;
obj = mxt_get_object(data,
MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71);
if(obj){
error = mxt_read_mem(data, obj->start_address,
MXT_PATCH_T71_DATA_MAX, buf);
if(!error){
#if MXT_PATCH_LOCK_CHECK
struct touch_pos* tpos = &tpos_data;
tpos->option = buf[MXT_PATCH_T71_PTN_OPT]; //1
tpos->cal_enable = buf[MXT_PATCH_T71_PTN_CAL]; //1
tpos->reset_cnt = buf[3]; //5
tpos->distance = buf[4]; //10
tpos->maxdiff = buf[5]; //10
tpos->locked_cnt = buf[6]; //40
tpos->jitter = buf[7]; //1
__mxt_patch_debug(data,
"PTN CAL %d RST %d DST %d DIF %d CNT %d JIT %d\n",
tpos->cal_enable, tpos->reset_cnt,
tpos->distance, tpos->maxdiff,
tpos->locked_cnt, tpos->jitter);
#endif
#if MXT_PATCH_SUPP_CHECK
tsupp_data.time_gap = buf[8]; //10
tsupp_data.repeat_max = buf[9]; //2
__mxt_patch_debug(data,
"SUPP GAP %d*100ms CNT %d\n",
tsupp_data.time_gap, tsupp_data.repeat_max);
#endif
}
}
}
/* Patch */
const char* mxt_patch_src_item_name(u8 src_id)
{
const char* src_item_name[MXT_PATCH_MAX_TYPE]={
MXT_XML_SRC_NONE, //MXT_PATCH_ITEM_NONE 0
MXT_XML_SRC_CHRG, //MXT_PATCH_ITEM_CHARGER 1
MXT_XML_SRC_FCNT, //MXT_PATCH_ITEM_FINGER_CNT 2
MXT_XML_SRC_AREA, //MXT_PATCH_ITEM_T9_AREA 3
MXT_XML_SRC_AMP, //MXT_PATCH_ITEM_T9_AMP 4
MXT_XML_SRC_SUM, //MXT_PATCH_ITEM_T57_SUM 5
MXT_XML_SRC_TCH, //MXT_PATCH_ITEM_T57_TCH 6
MXT_XML_SRC_ATCH, //MXT_PATCH_ITEM_T57_ATCH 7
MXT_XML_SRC_KCNT, //MXT_PATCH_ITEM_KCNT 8
MXT_XML_SRC_KVAL, //MXT_PATCH_ITEM_KVAL 9
};
if(MXT_PATCH_ITEM_NONE <= src_id &&
src_id < MXT_PATCH_ITEM_END){
return src_item_name[src_id];
}
return "ERR";
}
const char* mxt_patch_cond_name(u8 con_id)
{
const char* cond_name[MXT_PATCH_MAX_CON]={
MXT_XML_CON_NONE, //MXT_PATCH_CON_NONE 0
MXT_XML_CON_EQUAL, //MXT_PATCH_CON_EQUAL 1
MXT_XML_CON_BELOW, //MXT_PATCH_CON_BELOW 2
MXT_XML_CON_ABOVE, //MXT_PATCH_CON_ABOVE 3
MXT_XML_CON_PLUS, //MXT_PATCH_CON_PLUS 4
MXT_XML_CON_MINUS, //MXT_PATCH_CON_MINUS 5
MXT_XML_CON_MUL, //MXT_PATCH_CON_MUL 6
MXT_XML_CON_DIV, //MXT_PATCH_CON_DIV 7
MXT_XML_CON_MASK, //MXT_PATCH_CON_MASK 8
};
if(MXT_PATCH_CON_NONE <= con_id &&
con_id < MXT_PATCH_CON_END){
return cond_name[con_id];
}
return "ERR";
}
static int mxt_patch_item_lval(struct mxt_data *data,
u16* psrc_item, u8 src_id)
{
if(psrc_item != NULL){
if(MXT_PATCH_ITEM_NONE <= src_id &&
src_id < MXT_PATCH_ITEM_END){
return psrc_item[src_id];
}
else{
__mxt_patch_debug(data, "@@ INVALID ITEM ID=%d !!\n", src_id);
}
}
return 0;
}
static int mxt_patch_item_rval(struct mxt_data *data,
u16* psrc_item, struct item_val ival)
{
int lval = mxt_patch_item_lval(data, psrc_item, ival.val_id);
int rval = ival.val;
switch(ival.val_eq){
case MXT_PATCH_CON_NONE:
return lval ? lval : rval;
case MXT_PATCH_CON_PLUS:
lval += rval;
break;
case MXT_PATCH_CON_MINUS:
lval -= rval;
break;
case MXT_PATCH_CON_MUL:
lval *= rval;
break;
case MXT_PATCH_CON_DIV:
lval /= rval;
break;
default:
if(psrc_item){
__mxt_patch_debug(data, "@@ INVALID VAL_EQ=%d"
" (LVAL=%d) => RVAL=%d !!\n",
ival.val_eq, lval, rval);
}
return rval;
}
return lval;
}
static int mxt_patch_item_check(struct mxt_data *data,
u16* psrc_item, struct test_item* ptitem, bool do_action)
{
int lval = mxt_patch_item_lval(data, psrc_item, ptitem->src_id);
int rval = mxt_patch_item_rval(data, psrc_item, ptitem->ival);
if(!do_action){
__mxt_patch_debug(data, "|-- ITEM SRC_ID:%s COND:%s"
" VAL_ID:%s EQ:%s VAL:%d\n",
mxt_patch_src_item_name(ptitem->src_id),
mxt_patch_cond_name(ptitem->cond),
mxt_patch_src_item_name(ptitem->ival.val_id),
mxt_patch_cond_name(ptitem->ival.val_eq),
ptitem->ival.val);
}
if(psrc_item){
switch(ptitem->cond){
case MXT_PATCH_CON_EQUAL:
__mxt_patch_ddebug(data, "|--- IF %s: %d == %d = %d\n",
mxt_patch_src_item_name(ptitem->src_id),
lval, rval, lval == rval ? 1 : 0);
return lval == rval ? 1 : 0;
case MXT_PATCH_CON_BELOW:
__mxt_patch_ddebug(data, "|--- IF %s: %d < %d = %d\n",
mxt_patch_src_item_name(ptitem->src_id),
lval, rval, lval < rval ? 1 : 0);
return lval < rval ? 1 : 0;
case MXT_PATCH_CON_ABOVE:
__mxt_patch_ddebug(data, "|--- IF %s: %d > %d = %d\n",
mxt_patch_src_item_name(ptitem->src_id),
lval, rval, lval > rval ? 1 : 0);
return lval > rval ? 1 : 0;
case MXT_PATCH_CON_MASK:
__mxt_patch_ddebug(data, "|--- IF %s: %d & %d = %d\n",
mxt_patch_src_item_name(ptitem->src_id),
lval, rval, lval & rval ? 1 : 0);
return lval & rval ? 1 : 0;
default:
__mxt_patch_debug(data, "@@ INVALID TEST COND=%d !!\n",
ptitem->cond);
return -1;
}
}
return -1;
}
static int mxt_patch_stage_timer(struct mxt_data *data,
u16 period, bool do_action)
{
if(do_action){
int ret = 0;
u32 time = period * 10;
//__mxt_patch_debug(data, "STAGE[%d] TIMER: %dx10ms\n",
// data->patch.cur_stage, period);
ret = mxt_patch_start_timer(data, time);
if (!ret) {
data->patch.period = period;
}
}
return 0;
}
static void mxt_patch_dump_source(struct mxt_data *data,
bool do_action)
{
if(do_action){
__mxt_patch_debug(data, "TA:%d FCNT:%d AREA:%d AMP:%d"
" SUM:%d TCH:%d ATCH:%d KCNT:%d KVAL:%d\n",
data->patch.src_item[1], data->patch.src_item[2],
data->patch.src_item[3], data->patch.src_item[4],
data->patch.src_item[5], data->patch.src_item[6],
data->patch.src_item[7], data->patch.src_item[8],
data->patch.src_item[9]);
}
}
static int mxt_patch_parse_test_line(struct mxt_data *data,
u8* ppatch, u16* psrc_item, u16* check_cnt, bool do_action)
{
struct test_line* ptline;
struct test_item* ptitem;
struct action_cfg* pacfg;
u32 i=0, ulpos=0;
u8 test_result=0;
bool test_action=false;
ptline = (struct test_line*)ppatch;
if(!do_action){
__mxt_patch_debug(data, "|- TEST_LINE:%X OPT:%d CHK_CNT:%d"
" ITEM_CNT:%d CFG_CNT:%d ACTION:%d VAL:%d \n",
ptline->test_id, ptline->option, ptline->check_cnt,
ptline->item_cnt, ptline->cfg_cnt, ptline->act_id,
ptline->act_val);
}
ulpos += sizeof(struct test_line);
test_result = 0;
test_action = false;
for(i=0; i < ptline->item_cnt; i++){ /* Test Item Parsing */
ptitem = (struct test_item*)(ppatch+ulpos);
if(mxt_patch_item_check(data, psrc_item,
ptitem, do_action) > 0){
test_result++;
if(test_result == ptline->item_cnt){
if(check_cnt != NULL){
*check_cnt = *check_cnt+1;
if(*check_cnt == ptline->check_cnt){
test_action = true;
__mxt_patch_debug(data, "STAGE:%d TEST %d MATCHED",
data->patch.cur_stage, ptline->test_id);
mxt_patch_dump_source(data, test_action);
if(ptline->option&0x01){
*check_cnt=0;
__mxt_patch_ddebug(data, "CHEK CNT CLEAR\n");
}
}
}
}
}
else{
if(data->patch.option&0x04){
if(do_action&&psrc_item){// Skip if any item was failed
__mxt_patch_ddebug(data, "SKIP REMAINED ITEMS %d\n", i);
return 0;
}
}
}
ulpos += sizeof(struct test_item);
}
for(i=0; i <ptline->cfg_cnt; i++){ /* Test Line Action config */
pacfg = (struct action_cfg*)(ppatch+ulpos);
if(!do_action){
__mxt_patch_debug(data, "|-- ACTION_CFG: OBJ:%d"
" OFFSET:%d VAL:%d OPT:%d\n",
pacfg->obj_type, pacfg->offset,
pacfg->val, pacfg->option);
}
mxt_patch_write_action_cfg(data, pacfg, test_action);
ulpos += sizeof(struct action_cfg);
}
mxt_patch_predefined_action(data, ptline->act_id,
ptline->act_val, test_action);
return ulpos;
}
static int mxt_patch_parse_stage(struct mxt_data *data,
u8* ppatch, u16* ptline_addr, u8* ptline_cnt, bool do_action)
{
struct stage_def* psdef;
struct stage_cfg* pscfg;
u32 i=0, ulpos=0;
psdef = (struct stage_def*)ppatch;
if(!do_action){
__mxt_patch_debug(data,
"STAGE_ID:%d OPT:%d PERIOD:%d CFG_CNT:%d TST_CNT:%d RESET:%d\n",
psdef->stage_id, psdef->option, psdef->stage_period,
psdef->cfg_cnt, psdef->test_cnt, psdef->reset_period);//MXT_PATCH_STAGE_RESET
}
mxt_patch_stage_timer(data, psdef->stage_period, do_action);
ulpos += sizeof(struct stage_def);
for(i=0; i < psdef->cfg_cnt; i++){ /* Stage Config Parsing */
pscfg = (struct stage_cfg*)(ppatch+ulpos);
if(!do_action){
__mxt_patch_debug(data,
"|- STAGE_CFG: OBJ:%d OFFSET:%d VAL:%d OPT:%d\n",
pscfg->obj_type, pscfg->offset,
pscfg->val, pscfg->option);
}
mxt_patch_write_stage_cfg(data, pscfg, do_action);
ulpos += sizeof(struct stage_cfg);
}
for(i=0; i < psdef->test_cnt; i++){ /* Test Line Parsing */
if(ptline_addr != NULL){
ptline_addr[i] = (u16)ulpos;
//__mxt_patch_debug(data, "|- TEST LINE_ADDR: %d\n", ulpos);
}
ulpos += mxt_patch_parse_test_line(data,
ppatch+ulpos, NULL, NULL, do_action);
}
if(ptline_cnt != NULL)
*ptline_cnt = psdef->test_cnt;
return ulpos;
}
static u16 mxt_patch_match_lval(struct mxt_data *data,
u8* pmsg, u8 offset, u16 mask)
{
u16 lval=0;
u8 msg[MXT_PATCH_MAX_MSG_SIZE+1];
memset(msg, 0, MXT_PATCH_MAX_MSG_SIZE+1);
if(pmsg){
memcpy(msg, pmsg, MXT_PATCH_MAX_MSG_SIZE);
if(0 <= offset && offset < MXT_PATCH_MAX_MSG_SIZE){
lval = msg[offset] | (msg[offset+1] << 8);
return mask ? lval & mask : lval;
}
else{
__mxt_patch_debug(data, "@@ INVALID OFFSET=%d !!\n",
offset);
}
}
return 0;
}
static int mxt_patch_match_check(struct mxt_data *data,
u8* pmsg, struct match* pmatch, bool do_action)
{
u16 lval = mxt_patch_match_lval(data, pmsg,
pmatch->offset, pmatch->mask);
u16 rval = pmatch->val;
if(pmsg){
switch(pmatch->cond){
case MXT_PATCH_CON_EQUAL:
__mxt_patch_ddebug(data, "|--- IF %d == %d = %d\n",
lval, rval, lval == rval ? 1 : 0);
return lval == rval ? 1 : 0;
case MXT_PATCH_CON_BELOW:
__mxt_patch_ddebug(data, "|--- IF %d < %d = %d\n",
lval, rval, lval < rval ? 1 : 0);
return lval < rval ? 1 : 0;
case MXT_PATCH_CON_ABOVE:
__mxt_patch_ddebug(data, "|--- IF %d > %d = %d\n",
lval, rval, lval > rval ? 1 : 0);
return lval > rval ? 1 : 0;
default:
__mxt_patch_debug(data, "@@ INVALID MATCH COND=%d !!\n",
pmatch->cond);
return -1;
}
}
return -1;
}
static int mxt_patch_trigger_check(struct mxt_data *data,
u8 object, u8 index, u8* pmsg)
{
u8 reportid= pmsg[0];
u8 type, id;
type = data->reportids[reportid].type;
id = data->reportids[reportid].index;
if((type == object)&&(id == index))
return 0;
return 1;
}
static int mxt_patch_parse_trigger(struct mxt_data *data,
u8* ppatch, u8* pmsg, bool do_action, u8 option)
{
struct trigger* ptrgg;
struct match* pmatch;
struct trigger_cfg* ptcfg;
u32 i=0, ulpos=0;
u8 match_result=0;
u8 trigger_action=0;
ptrgg = (struct trigger*)ppatch;
if(!do_action){
__mxt_patch_debug(data, "TRIGGER ID:%d OPT:%d OBJ:%d IDX:%d "
"MATCH:%d CFG:%d ACT:%d VAL:%d\n",
ptrgg->tid, ptrgg->option, ptrgg->object,
ptrgg->index, ptrgg->match_cnt, ptrgg->cfg_cnt,
ptrgg->act_id, ptrgg->act_val);
}
ulpos += sizeof(struct trigger);
// Message Filter
if(do_action){
if(mxt_patch_trigger_check(data,
ptrgg->object, ptrgg->index, pmsg))
return 1;
}
// Match Parsing
match_result=0;
trigger_action=false;
for(i=0; i < ptrgg->match_cnt; i++){
pmatch = (struct match*)(ppatch+ulpos);
if(!do_action){
__mxt_patch_debug(data, "|- MATCH:%d OFFSET:%d MASK:%d"
" COND:%s VAL:%d\n", i,
pmatch->offset, pmatch->mask,
mxt_patch_cond_name(pmatch->cond), pmatch->val);
}
if(mxt_patch_match_check(data, pmsg, pmatch, do_action) > 0){
match_result++;
if(match_result == ptrgg->match_cnt){
if(option == ptrgg->option)
trigger_action = true;
}
}
ulpos += sizeof(struct match);
}
// Trigger Config Parsing
for(i=0; i < ptrgg->cfg_cnt; i++){
ptcfg = (struct trigger_cfg*)(ppatch+ulpos);
if(!do_action){
__mxt_patch_debug(data, "|- TRIGGER_CFG: OBJECT_TYPE:%d"
" OFFSET:%d VAL:%d\n",
ptcfg->obj_type, ptcfg->offset, ptcfg->val);
}
mxt_patch_write_trigger_cfg(data, ptcfg, trigger_action);
ulpos += sizeof(struct trigger_cfg);
}
// Predefined Action
mxt_patch_predefined_action(data, ptrgg->act_id,
ptrgg->act_val, trigger_action);
return ulpos;
}
int mxt_patch_parse_event(struct mxt_data *data,
u8* ppatch, bool do_action)
{
struct user_event* pevent;
struct event_cfg* pecfg;
u32 i=0, ulpos=0;
pevent = (struct user_event*)ppatch;
if(!do_action){
__mxt_patch_debug(data, "EVENT ID:%d OPT:%d CFG:%d\n",
pevent->eid, pevent->option, pevent->cfg_cnt);
}
ulpos += sizeof(struct user_event);
// Event Config Parsing
for(i=0; i < pevent->cfg_cnt; i++){
pecfg = (struct event_cfg*)(ppatch+ulpos);
if(!do_action){
__mxt_patch_debug(data, "|- EVENT_CFG: "
"OBJECT_TYPE:%d OFFSET:%d VAL:%d\n",
pecfg->obj_type, pecfg->offset, pecfg->val);
}
mxt_patch_write_event_cfg(data, pecfg, do_action);
ulpos += sizeof(struct event_cfg);
}
return ulpos;
}
static int mxt_patch_parse_header(struct mxt_data *data,
u8* ppatch, u16* pstage_addr, u16* ptrigger_addr,
u16* pevent_addr)
{
struct patch_header* ppheader;
u32 i=0, ulpos=0;
ppheader = (struct patch_header*)ppatch;
dev_info(&data->client->dev, "PATCH MAGIC:%X SIZE:%d DATE:%d"
" VER:%d OPT:%d DBG:%d TMR:%d STG:%d TRG:%d EVT:%d\n",
ppheader->magic, ppheader->size, ppheader->date,
ppheader->version, ppheader->option, ppheader->debug,
ppheader->timer_id, ppheader->stage_cnt, ppheader->trigger_cnt,
ppheader->event_cnt);
if(ppheader->version != MXT_PATCH_VERSION){
dev_err(&data->client->dev, "MXT_PATCH_VERSION ERR\n");
}
ulpos = sizeof(struct patch_header);
for(i=0; i < ppheader->stage_cnt; i++){ /* Stage Def Parsing */
if(pstage_addr != NULL){
pstage_addr[i] = (u16)ulpos;
//__mxt_patch_debug(data, "STAGE_ADDR: %d\n", ulpos);
}
ulpos += mxt_patch_parse_stage(data, ppatch+ulpos,
NULL, NULL, false);
}
for(i=0; i < ppheader->trigger_cnt; i++){ /* Trigger Parsing */
if(ptrigger_addr != NULL){
ptrigger_addr[i] = (u16)ulpos;
//__mxt_patch_debug(data, "TRIGGER_ADDR: %d\n", ulpos);
}
ulpos += mxt_patch_parse_trigger(data, ppatch+ulpos,
NULL, false, 0);
}
for(i=0; i < ppheader->event_cnt; i++){ /* Event */
if(pevent_addr != NULL){
pevent_addr[i] = (u16)ulpos;
//__mxt_patch_debug(data, "EVENT_ADDR: %d\n", ulpos);
}
ulpos += mxt_patch_parse_event(data, ppatch+ulpos, false);
}
if(ppheader->size != ulpos){ /* Patch Size Check */
__mxt_patch_debug(data, "PATCH SIZE ERROR %d != %d\n\n",
ppheader->size, ulpos);
return 0;
}
else{
__mxt_patch_debug(data, "PATCH SIZE OK= %d\n\n", ulpos);
}
return ulpos;
}
static int mxt_patch_run_stage(struct mxt_data *data)
{
struct stage_def* psdef=NULL;
u8* ppatch = data->patch.patch;
u16* pstage_addr = data->patch.stage_addr;
u16 tline_addr[MXT_PATCH_MAX_TLINE];
u8 tline_cnt;
u8 cur_stage = data->patch.cur_stage;
//__mxt_patch_debug(data, "RUN STAGE:%d\n", cur_stage);
if(!ppatch || !pstage_addr){
dev_err(&data->client->dev, "%s pstage_addr is null\n", __func__);
return 1;
}
psdef = (struct stage_def*)(ppatch+pstage_addr[cur_stage]);
data->patch.cur_stage_opt = psdef->option;
mxt_patch_parse_stage(data, (u8*)psdef, tline_addr, &tline_cnt, true);
if(!data->patch.tline_addr){
kfree(data->patch.tline_addr);
}
if(!data->patch.check_cnt){
kfree(data->patch.check_cnt);
}
data->patch.tline_addr = kzalloc(tline_cnt*sizeof(u16), GFP_KERNEL);
data->patch.check_cnt = kzalloc(tline_cnt*sizeof(u16), GFP_KERNEL);
if (!data->patch.tline_addr || !data->patch.check_cnt){
dev_err(&data->client->dev, "tline_addr alloc error\n");
return 1;
}
memcpy(data->patch.tline_addr, tline_addr, tline_cnt*sizeof(u16));
memset(data->patch.check_cnt, 0, tline_cnt*sizeof(u16));
data->patch.tline_cnt = tline_cnt;
data->patch.run_stage = 1;
data->patch.skip_test = 0;
#if MXT_PATCH_STAGE_RESET
data->patch.stage_timestamp = jiffies_to_msecs(jiffies);
__mxt_patch_ddebug(data, "Stage[%d] %d\n",
cur_stage, data->patch.stage_timestamp);
#endif
return 0;
}
static int mxt_patch_test_source(struct mxt_data *data, u16* psrc_item)
{
int i;
u8* ppatch = data->patch.patch;
u16* pstage_addr = data->patch.stage_addr;
u8 cur_stage = data->patch.cur_stage;
#if MXT_PATCH_STAGE_RESET
u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff = TIME_WRAP_AROUND(data->patch.stage_timestamp, curr_time);
struct stage_def* psdef=NULL;
#endif
if(!ppatch || !pstage_addr){
dev_err(&data->client->dev, "%s pstage_addr is null\n", __func__);
return 1;
}
if(!data->patch.run_stage){
mxt_patch_run_stage(data);
}
if(data->patch.run_stage){
for(i=0; i< data->patch.tline_cnt; i++){
u16* ptline_addr = data->patch.tline_addr;
u16* pcheck_cnt = data->patch.check_cnt;
if(!ptline_addr || !pcheck_cnt){
dev_err(&data->client->dev, "ptline_addr is null\n");
return 1;
}
__mxt_patch_ddebug(data, "STAGE:%d, TEST:%d\n", cur_stage, i);
mxt_patch_parse_test_line(data,
ppatch+pstage_addr[cur_stage]+ptline_addr[i],
psrc_item, &pcheck_cnt[i], true);
#if MXT_PATCH_STAGE_RESET
psdef = (struct stage_def*)(ppatch+pstage_addr[cur_stage]);
if(psdef->reset_period){
if(time_diff > psdef->reset_period*10){
pcheck_cnt[i] = 0;
__mxt_patch_ddebug(data,
"RESET CNT STAGE:%d, TEST:%d RESET:%d DIF:%d\n",
cur_stage, i,
psdef->reset_period, time_diff);
data->patch.stage_timestamp = jiffies_to_msecs(jiffies);
}
}
#endif
if(data->patch.skip_test){
__mxt_patch_debug(data, "REMAINED TEST SKIP\n");
return 0;
}
}
}
return 0;
}
static void mxt_patch_init_tsrc(struct test_src* tsrc)
{
tsrc->charger=-1;
tsrc->finger_cnt=-1;
tsrc->area=-1;
tsrc->amp=-1;
tsrc->sum_size=-1;
tsrc->tch_ch=-1;
tsrc->atch_ch=-1;
tsrc->key_cnt=-1;
tsrc->key_val=-1;
}
static int mxt_patch_make_source(struct mxt_data *data,
struct test_src* tsrc)
{
if(tsrc->charger >= 0)
data->patch.src_item[MXT_PATCH_ITEM_CHARG]= tsrc->charger;
if(tsrc->finger_cnt >= 0)
data->patch.src_item[MXT_PATCH_ITEM_FCNT]= tsrc->finger_cnt;
if(tsrc->area >= 0)
data->patch.src_item[MXT_PATCH_ITEM_AREA]= tsrc->area;
if(tsrc->amp >= 0)
data->patch.src_item[MXT_PATCH_ITEM_AMP]= tsrc->amp;
if(tsrc->sum_size >= 0)
data->patch.src_item[MXT_PATCH_ITEM_SUM]= tsrc->sum_size;
if(tsrc->tch_ch >= 0)
data->patch.src_item[MXT_PATCH_ITEM_TCH]= tsrc->tch_ch;
if(tsrc->atch_ch >= 0)
data->patch.src_item[MXT_PATCH_ITEM_ATCH]= tsrc->atch_ch;
if(tsrc->key_cnt >= 0)
data->patch.src_item[MXT_PATCH_ITEM_KCNT]= tsrc->key_cnt;
if(tsrc->key_val >= 0)
data->patch.src_item[MXT_PATCH_ITEM_KVAL]= tsrc->key_val;
//mxt_patch_dump_source(data, true);
return 0;
}
static int mxt_patch_start_stage(struct mxt_data *data)
{
if(data->patch.patch){
mxt_patch_stop_timer(data);
data->patch.start = true;
data->patch.cur_stage = 0;
data->patch.run_stage = false;
if(data->patch.start_stage){
data->patch.cur_stage = data->patch.start_stage;
}
__mxt_patch_debug(data, "PATCH: START STAGE %d\n",
data->patch.cur_stage);
#if MXT_PATCH_LOCK_CHECK
mxt_patch_init_tpos(data, &tpos_data);
#endif
#if MXT_PATCH_SUPP_CHECK
mxt_patch_init_supp(data, &tsupp_data);
#endif
return 0;
}
return 1;
}
static int mxt_patch_test_trigger(struct mxt_data *data,
struct mxt_message *message, u8 option)
{
int i;
u8* ppatch = data->patch.patch;
u16* ptrigger_addr = data->patch.trigger_addr;
u8 trigger_cnt = data->patch.trigger_cnt;
u8 tmsg[MXT_PATCH_MAX_MSG_SIZE];
if(!ppatch || !ptrigger_addr){
dev_err(&data->client->dev, "%s ptrigger_addr is null\n",
__func__);
return 1;
}
memset(tmsg, 0, MXT_PATCH_MAX_MSG_SIZE);
tmsg[0] = message->reportid;
memcpy(&tmsg[1], message->message, 8);
for(i=0; i< trigger_cnt; i++){
//__mxt_patch_debug(data, "TRIGGER:%d\n", i);
mxt_patch_parse_trigger(data, ppatch+ptrigger_addr[i],
tmsg, true, option);
}
return 0;
}
static int mxt_patch_test_event(struct mxt_data *data,
u8 event_id)
{
u8* ppatch = data->patch.patch;
u16* pevent_addr = data->patch.event_addr;
if(!ppatch || !pevent_addr){
dev_err(&data->client->dev, "%s pevent_addr is null\n",
__func__);
return 1;
}
if(event_id < data->patch.event_cnt){
mxt_patch_parse_event(data, ppatch+pevent_addr[event_id],
true);
}
return 0;
}
static void mxt_patch_T6_object(struct mxt_data *data,
struct mxt_message *message)
{
/* Normal mode */
if (message->message[0] == 0x00) {
//__mxt_patch_debug(data, "PATCH: NORMAL\n");
#if 0 //Event Test
if(data->patch.event_cnt)
mxt_patch_test_event(data, 0);
#endif
}
/* Calibration */
if (message->message[0] & 0x10){
__mxt_patch_debug(data, "PATCH: CAL\n");
mxt_patch_start_stage(data);
}
/* Reset */
if (message->message[0] & 0x80) {
__mxt_patch_debug(data, "PATCH: RESET\n");
data->patch.start_stage = 0;
mxt_patch_start_stage(data);
}
}
static void mxt_patch_T9_object(struct mxt_data *data,
struct mxt_message *message)
{
int id;
u8 *msg = message->message;
struct test_src tsrc;
id = data->reportids[message->reportid].index;
mxt_patch_init_tsrc(&tsrc);
tsrc.area = msg[4];
tsrc.amp = msg[5];
if(data->patch.start){
mxt_patch_make_source(data, &tsrc);
#if MXT_PATCH_SUPP_CHECK
if(data->patch.cur_stage_opt&0x02){
if((msg[0] & MXT_DETECT_MSG_MASK) != MXT_DETECT_MSG_MASK){
if (msg[0] & MXT_SUPPRESS_MSG_MASK){
mxt_patch_check_supp(data, &tsupp_data);
}
}
}
#endif
}
}
static void mxt_patch_T15_object(struct mxt_data *data,
struct mxt_message *message)
{
struct test_src tsrc;
unsigned long keystates = message->message[MXT_MSG_T15_KEYSTATE];
u8 key_cnt=0;
int i;
for(i=0; i < 8; i++){
if(test_bit(i, &keystates)){
key_cnt++;
}
}
mxt_patch_init_tsrc(&tsrc);
tsrc.key_cnt = key_cnt;
tsrc.key_val = keystates;
if(data->patch.start){
mxt_patch_make_source(data, &tsrc);
if(data->patch.option&0x02) //0905#2
mxt_patch_test_source(data, data->patch.src_item);
}
}
static void mxt_patch_T57_object(struct mxt_data *data,
struct mxt_message *message)
{
struct test_src tsrc;
u8 *msg = message->message;
u8 finger_cnt = 0;
int i;
mxt_patch_init_tsrc(&tsrc);
for (i = 0; i < MXT_MAX_FINGER; i++) {
if ((data->fingers[i].state != MXT_STATE_INACTIVE) &&
(data->fingers[i].state != MXT_STATE_RELEASE))
finger_cnt++;
}
#if TSP_INFORM_CHARGER
tsrc.charger = data->charging_mode;
#endif
tsrc.finger_cnt = finger_cnt;
tsrc.sum_size = msg[0] | (msg[1] << 8);
tsrc.tch_ch = msg[2] | (msg[3] << 8);
tsrc.atch_ch = msg[4] | (msg[5] << 8);
if(data->patch.start){
if((data->patch.option & 0x01)== 0x01 && !finger_cnt)
return;
mxt_patch_make_source(data, &tsrc);
mxt_patch_test_source(data, data->patch.src_item);
}
#if MXT_PATCH_LOCK_CHECK
if(data->patch.cur_stage_opt&0x01){
if(finger_cnt){
for (i = 0; i < MXT_MAX_FINGER; i++) {
if ((data->fingers[i].state != MXT_STATE_INACTIVE) &&
(data->fingers[i].state != MXT_STATE_RELEASE)){
mxt_patch_check_pattern(data, &tpos_data, i,
data->fingers[i].x, data->fingers[i].y, finger_cnt);
}
}
}
else{
mxt_patch_init_tpos(data, &tpos_data);
}
}
#endif
}
static void mxt_patch_T61_object(struct mxt_data *data,
struct mxt_message *message)
{
int id;
u8 *msg = message->message;
id = data->reportids[message->reportid].index;
if ((id != data->patch.timer_id) || ((msg[0] & 0xa0) != 0xa0))
return;
__mxt_patch_debug(data, "END STAGE %d TIMER\n",
data->patch.cur_stage);
if((data->patch.cur_stage+1) == data->patch.stage_cnt){
if(data->patch.period == 0){
__mxt_patch_debug(data, "EX-STAGE\n");
}
else{
data->patch.start = false;
__mxt_patch_debug(data, "END ALL STAGE\n");
}
}
else{
data->patch.cur_stage++;
data->patch.run_stage = false;
}
if(!data->patch.run_stage){
mxt_patch_run_stage(data);
}
}
static void mxt_patch_message(struct mxt_data *data,
struct mxt_message *message)
{
u8 reportid, type;
reportid = message->reportid;
if (reportid > data->max_reportid)
return;
type = data->reportids[reportid].type;
switch (type) {
case MXT_GEN_COMMANDPROCESSOR_T6:
mxt_patch_T6_object(data, message);
break;
case MXT_TOUCH_MULTITOUCHSCREEN_T9:
mxt_patch_T9_object(data, message);
break;
case MXT_TOUCH_KEYARRAY_T15:
mxt_patch_T15_object(data, message);
break;
case MXT_PROCI_EXTRATOUCHSCREENDATA_T57:
mxt_patch_T57_object(data, message);
break;
case MXT_SPT_TIMER_T61:
mxt_patch_T61_object(data, message);
break;
}
if(data->patch.trigger_cnt && type){
u8 option=0;
#if TSP_INFORM_CHARGER
option = data->charging_mode;
#endif
mxt_patch_test_trigger(data, message, option);
}
}
static int mxt_patch_init(struct mxt_data *data, u8* ppatch)
{
struct mxt_patch* patch_info= &data->patch;
struct patch_header* ppheader;
u16 stage_addr[32];
u16 trigger_addr[32];
u16 event_addr[32];
u32 patch_size=0;
if(!ppatch){
dev_info(&data->client->dev, "%s patch file error\n", __func__);
return 1;
}
patch_size = mxt_patch_parse_header(data,
ppatch, stage_addr, trigger_addr, event_addr);
if(!patch_size){
dev_info(&data->client->dev, "%s patch_size error\n", __func__);
return 1;
}
ppheader = (struct patch_header*)ppatch;
patch_info->timer_id = ppheader->timer_id;
patch_info->option = ppheader->option;
patch_info->debug = ppheader->debug;
patch_info->stage_cnt = ppheader->stage_cnt;
patch_info->trigger_cnt = ppheader->trigger_cnt;
patch_info->event_cnt = ppheader->event_cnt;
if(!data->patch.src_item){
kfree(data->patch.src_item);
}
patch_info->src_item = kzalloc(MXT_PATCH_ITEM_END*sizeof(u16),
GFP_KERNEL);
if(patch_info->stage_cnt){
if(!patch_info->stage_addr){
kfree(patch_info->stage_addr);
}
patch_info->stage_addr =
kzalloc(patch_info->stage_cnt*sizeof(u16), GFP_KERNEL);
if (!patch_info->stage_addr) {
dev_err(&data->client->dev, "stage_addr alloc error\n");
return 1;
}
memcpy(patch_info->stage_addr, stage_addr,
patch_info->stage_cnt*sizeof(u16));
}
if(patch_info->trigger_cnt){
if(!patch_info->trigger_addr){
kfree(patch_info->trigger_addr);
}
patch_info->trigger_addr =
kzalloc(patch_info->trigger_cnt*sizeof(u16), GFP_KERNEL);
if (!patch_info->trigger_addr) {
dev_err(&data->client->dev, "trigger_addr alloc error\n");
return 1;
}
memcpy(patch_info->trigger_addr, trigger_addr,
patch_info->trigger_cnt*sizeof(u16));
}
if(patch_info->event_cnt){
if(!patch_info->event_addr){
kfree(patch_info->event_addr);
}
patch_info->event_addr =
kzalloc(patch_info->event_cnt*sizeof(u16), GFP_KERNEL);
if (!patch_info->event_addr) {
dev_err(&data->client->dev, "event_addr alloc error\n");
return 1;
}
memcpy(patch_info->event_addr, event_addr,
patch_info->event_cnt*sizeof(u16));
}
mxt_patch_load_t71data(data);
return 0;
}
#endif