text: #include "linux/module.h"
  
  //#define	GESTURE_ABLE	1
  #define	GESTURE_LICH	1
  
  #ifndef GSL_VERSION
  #define GSL_VERSION		0x20140829
  #endif
  #ifndef NULL
  #define	NULL  ((void*)0)
  #endif
  #ifndef UINT
  #define	UINT  unsigned int
  #endif
  
  #define	POINT_MAX		10
  #define	PP_DEEP			10
  #define	PS_DEEP			10
  #define PR_DEEP			10
  #define POINT_DEEP		(PP_DEEP + PS_DEEP + PR_DEEP)
  #define	PRESSURE_DEEP	8
  #define	CONFIG_LENGTH	512
  #define TRUE			1
  #define FALSE			0
  #define FLAG_ABLE		(0x4<<12)
  #define FLAG_FILL		(0x2<<12)
  #define	FLAG_KEY		(0x1<<12)
  #define	FLAG_COOR		(0x0fff0fff)
  #define	FLAG_COOR_EX	(0xffff0fff)
  #define	FLAG_ID			(0xf0000000)
  
  struct gsl_touch_info
  {
  	int x[10];
  	int y[10];
  	int id[10];
  	int finger_num;	
  };
  
  typedef struct
  {
  	unsigned int i;
  	unsigned int j;
  	unsigned int min;//distance min
  	unsigned int d[POINT_MAX][POINT_MAX];//distance;
  }gsl_DISTANCE_TYPE;
  
  typedef union
  {
  	struct
  	{
  		unsigned y:12;
  		unsigned key:1;
  		unsigned fill:1;
  		unsigned able:1;
  		unsigned predict:1;
  		unsigned x:16;
  	};
  	struct
  	{
  		unsigned y:13;
  		unsigned rev_2:3;
  		unsigned x:16;
  	}dis;
  	unsigned int all;
  }gsl_POINT_TYPE;
  
  typedef union
  {
  	struct
  	{
  		unsigned delay:8;
  		unsigned report:8;
  		unsigned rev_1:14;
  		unsigned able:1;
  		unsigned init:1;
  	};
  	unsigned int all;
  }gsl_DELAY_TYPE;
  
  typedef union
  {
  	struct
  	{
  		unsigned rev_0:8;
  		unsigned rev_1:8;
  
  		unsigned rev_2:7;
  		unsigned ex:1;
  
  		unsigned interpolation:4;
  		unsigned rev_3:1;
  		unsigned only:1;
  		unsigned mask:1;
  		unsigned reset:1;
  	};
  	unsigned int all;
  }gsl_STATE_TYPE;
  
  typedef struct
  {
  	unsigned int rate;
  	unsigned int dis;
  	gsl_POINT_TYPE coor;
  }gsl_EDGE_TYPE;
  
  typedef union
  {
  	struct  
  	{
  		short y;
  		short x;
  	};
  	unsigned int all;
  }gsl_DECIMAL_TYPE;
  
  typedef union
  {
  	struct
  	{
  			unsigned over_report_mask:1;
  			unsigned opposite_x:1;
  			unsigned opposite_y:1;
  			unsigned opposite_xy:1;
  			unsigned line:1;
  			unsigned line_neg:1;
  			unsigned line_half:1;
  			unsigned middle_drv:1;
  			
  			unsigned key_only_one:1;
  			unsigned key_line:1;
  			unsigned refe_rt:1;
  			unsigned refe_var:1;
  			unsigned base_median:1;
  			unsigned key_rt:1;
  			unsigned refe_reset:1;
  			unsigned sub_cross:1;
  			
  			unsigned row_neg:1;
  			unsigned sub_line_coe:1;
  			unsigned sub_row_coe:1;
  			unsigned c2f_able:1;
  			unsigned thumb:1;
  			unsigned graph_h:1;
  			unsigned init_repeat:1;
  			unsigned near_reset_able:1;
  			
  			unsigned emb_dead:1; 
  			unsigned emb_point_mask:1; 
  			unsigned interpolation:1;
  			unsigned sum2_able:1;
  			unsigned reduce_pin:1;
  			unsigned drv_order_ex:1;
  			unsigned id_over:1;
  			unsigned rev_1:1;
  	};
  	unsigned int all;
  }gsl_FLAG_TYPE;
  
  static gsl_POINT_TYPE point_array[POINT_DEEP][POINT_MAX];
  static gsl_POINT_TYPE *point_pointer[PP_DEEP];
  static gsl_POINT_TYPE *point_stretch[PS_DEEP];
  static gsl_POINT_TYPE *point_report[PR_DEEP];
  static gsl_POINT_TYPE point_now[POINT_MAX];
  static gsl_DELAY_TYPE point_delay[POINT_MAX];
  static int filter_deep[POINT_MAX];
  static gsl_EDGE_TYPE point_edge;
  static gsl_DECIMAL_TYPE point_decimal[POINT_MAX];
  
  static unsigned int pressure_now[POINT_MAX];
  static unsigned int pressure_array[PRESSURE_DEEP][POINT_MAX];
  static unsigned int pressure_report[POINT_MAX];
  static unsigned int *pressure_pointer[PRESSURE_DEEP];
  
  #define	pp							point_pointer
  #define	ps							point_stretch
  #define	pr							point_report
  #define	point_predict				pp[0]
  #define	pa							pressure_pointer
  
  static	gsl_STATE_TYPE global_state;
  static	int inte_count;
  static	unsigned int csensor_count;
  static	unsigned int click_count[4];
  static	gsl_POINT_TYPE point_click[4];
  static	unsigned int double_click;
  static	int point_n;
  static	int point_num;
  static	int prev_num;
  static	int point_near;
  static	unsigned int point_shake;
  static	unsigned int reset_mask_send;
  static	unsigned int reset_mask_max;
  static	unsigned int reset_mask_count;
  static	gsl_FLAG_TYPE global_flag;
  static	unsigned int id_first_coe;
  static	unsigned int id_speed_coe;
  static	unsigned int id_static_coe;
  static	unsigned int average;
  static	unsigned int soft_average;
  static	unsigned int report_delay;
  static	unsigned int report_ahead;
  static	unsigned char median_dis[4];
  static	unsigned int shake_min;
  static	int match_y[2];
  static	int match_x[2];
  static	int ignore_y[2];
  static	int ignore_x[2];
  static	int screen_y_max;
  static	int screen_x_max;
  static	int point_num_max;
  static	unsigned int drv_num;
  static	unsigned int sen_num;
  static	unsigned int drv_num_nokey;
  static	unsigned int sen_num_nokey;
  static	unsigned int coordinate_correct_able;
  static	unsigned int coordinate_correct_coe_x[64];
  static	unsigned int coordinate_correct_coe_y[64];
  static	unsigned int edge_cut[4];
  static	unsigned int stretch_array[4*4*2];
  static	unsigned int shake_all_array[2*8];
  static	unsigned int reset_mask_dis;
  static	unsigned int reset_mask_type;
  static	unsigned int key_map_able;
  static	unsigned int key_range_array[8*3];
  static	int  filter_able;
  static	unsigned int filter_coe[4];
  static	unsigned int multi_x_array[4],multi_y_array[4];
  static	unsigned int multi_group[4][64];
  static	int ps_coe[4][8],pr_coe[4][8];
  static	int point_repeat[2];
  static	int near_set[2];
  static	int diagonal;
  static	int point_extend;
  // 	unsigned int key_dead_time			;
  // 	unsigned int point_dead_time		;
  // 	unsigned int point_dead_time2		;
  // 	unsigned int point_dead_distance	;
  // 	unsigned int point_dead_distance2	;
  // 	unsigned int pressure_able;
  // 	unsigned int pressure_save[POINT_MAX];
  static	unsigned int edge_first;
  static	unsigned int edge_first_coe;
  
  static	unsigned int point_corner;
  //-------------------------------------------------
  static	unsigned int config_static[CONFIG_LENGTH];
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  #ifdef GESTURE_LICH
  #define	GESTURE_BUF_SIZE		256
  #define	GESTURE_SIZE_REFE		255
  #define	GESTURE_SIZE_NUM		32
  #define	GESTURE_XY				0x1
  #define	GESTURE_DEAL			0x2
  #define	GESTURE_LRUD			0x4
  #define	GESTURE_ALL				0x7fffffff
  typedef union
  {
  	struct
  	{
  		unsigned y:12;
  		unsigned rev:4;
  		unsigned x:16;
  	};
  	unsigned int all;
  }GESTURE_POINT_TYPE;
  typedef struct  
  {
  	int coe;
  	int out;
  	unsigned int coor[GESTURE_SIZE_NUM/2];
  }GESTURE_MODEL_TYPE;
  //GESTURE_POINT_TYPE gesture_buf[GESTURE_BUF_SIZE];//gesture_buf
  #define	gesture_buf				((GESTURE_POINT_TYPE*)config_static)
  #define	gesture_standard		((GESTURE_POINT_TYPE*)(&config_static[GESTURE_BUF_SIZE]))
  static int  gesture_num,gesture_num_last;//gesture_num
  static int  gesture_dis_min;
  static int  gesture_deal;
  static int  gesture_last=0,gesture_value=0;
  static int  gesture_threshold[2];
  static  int x_scale;
  static  int y_scale;
  static int double_down,double_up;
  typedef struct
  {
  	int dis;
  	int count;
  }GESTURE_MULTI_TYPE;
  static GESTURE_MULTI_TYPE multi_x[5];
  static GESTURE_MULTI_TYPE multi_o[5];
  static int gesture_multi = 0;
  static unsigned int multi_set = 0;
  static unsigned int gesture_flag = 0;
  static const GESTURE_MODEL_TYPE * model_extern = NULL;
  static int  model_extern_len = 0;
  static int  GestureSqrt(int d);
  static int  GestureDistance(GESTURE_POINT_TYPE* d1,GESTURE_POINT_TYPE* d2,int sqrt_able);
  static int  GesturePush(GESTURE_POINT_TYPE* data);
  static int  GestureStretch(void);
  static int  GestureLength(void);
  static int  GestureDeal(void);
  static int	GestureModel(const GESTURE_MODEL_TYPE * model,int len,int threshold,int *out);
  static int  GestureMain(unsigned int data[],unsigned int pn);
  static void GestureStandard(void);
  static void GestureInit(void);
  static void ChangeXY(void);
  static int  GestureLRUD(void);
  static void GestureSet(unsigned int conf[]);
  static int  GestureMulti(unsigned int *data_in);
  static void GestureOrientation(int ori);
  static int GestureJoint(void);
  static unsigned int (*ReadIICInt) (unsigned int *data,unsigned int addr,unsigned int len); 
  static const GESTURE_MODEL_TYPE model_default[]
  ={
  		{0x10,'3',{
  		0x37170105,0x78580000,0xba990a03,0xedd92e14,0xb9d85347,0x7798655b,0x3657716b,0x1f156d74,
  		0x60406969,0xa2816f69,0xe3c28075,0xf9fbb899,0xc3e3e0d2,0x83a4f6ee,0x4262fffc,0x0021f7fd,}},
  		{0x10,'6',{
  		0xa2be0400,0x70881f10,0x4258402e,0x1d2e6c54,0x040ea084,0x0a01d6bc,0x381df9ec,0x7054fffd,
  		0xa88cfafe,0xdac2ddef,0xfff0b2cb,0xe2f78497,0xaac7747a,0x728e7472,0x3b56817b,0x0420968b,}},
  		{0x10,'7',{
  		0x12000001,0x37240000,0x5b490000,0x806e0000,0xa5930000,0xcab70000,0xefdc0300,0xf9fd1f0e,
  		0xe2ee3d30,0xc5d4564a,0xa7b76c61,0x8c9a8579,0x717e9f93,0x5863bbad,0x434cdbc9,0x3c3dffec,}},
  		{0x10,'8',{
  		0xdaff030c,0x8eb40000,0x41670c06,0x001c3116,0x431e5448,0x8f69635d,0xd1b58a6f,0xcedfd0af,
  		0x88acf5e6,0x3c62fffd,0x0718cdf1,0x341493aa,0x7a556d7d,0xc19e4f60,0xf9e51c3c,0xb5dc0005,}},	
  		{0x10,'8',{
  		0x627d231e,0x2f49382c,0x03175a48,0x21098172,0x563c958c,0x856eb0a2,0x8f99dac4,0x5b76eee5,
  		0x243ffdf5,0x090ddbf4,0x2918acc2,0x4d3a8497,0x78636172,0xa38e4050,0xd0ba1f2e,0xffe7000f,}},
  		{0x10,'9',{
  		0xe8ff0715,0xb4ce0001,0x819a0500,0x4f68150c,0x1e362a1e,0x000c543c,0x270d7169,0x5b417273,
  		0x9076666d,0xbda74a5a,0xddcf1e36,0xc8d7321b,0xb4be634b,0xa4ac967d,0x959ccab0,0x898fffe4,}},
  		{0x10,'A',{
  		0xaeca000b,0x74900e02,0x41582d1b,0x182a5942,0x02099375,0x0600cfb1,0x2c15fcea,0x664af1fe,
  		0x957ec8dd,0xb5a894b0,0xc9bf5876,0xd7d31c3a,0xd4d75134,0xd3d38d6f,0xdbd4c9ab,0xffe9fce6,}},
  		{0x10,'A',{
  		0x8eab0102,0x56711307,0x2c3f3a25,0x0e1b6b51,0x0004a689,0x0e02ddc2,0x3e22fbf2,0x725be8fa,
  		0x9284b6d0,0xa69d7f9b,0xb3ae4562,0xb7b80b28,0xa7a6290c,0xb1aa6346,0xd0be947d,0xffe7bba7,}},
  		{0x10,'B',{
  		0x56591a00,0x474e4e35,0x343f8168,0x242cb59c,0x0f1be7ce,0x170ddbf4,0x3c25b4c4,0x6e549ca6,
  		0xa3889799,0xd8bd9d96,0xfcf1bea8,0xd3e9e4d4,0xa0baf6f0,0x6b85fcfa,0x3650fffd,0x001bfbff,}},
  		{0x10,'C',{
  		0xfaff2337,0xdaec0913,0xb0c50003,0x879c0500,0x5f720f09,0x3b4c271a,0x1d2b4534,0x08116a56,
  		0x0003937f,0x0a03bca8,0x2515ddce,0x4b38f2e8,0x7560fff9,0x9e89f7fd,0xc6b2e8f0,0xeed9d7df,}},
  		{0x10,'C',{
  		0xacbf0100,0x86990a04,0x64751b12,0x45533225,0x2b375141,0x17217160,0x080f9582,0x0103bba8,
  		0x0200e2cf,0x200ff9f1,0x4633fefc,0x6c59ffff,0x9380fcfd,0xb9a6f4f9,0xdccbe4ed,0xffeeceda,}},
  		{0x10,'C',{
  		0x57670a00,0x3a492116,0x222d3d2e,0x0f175e4d,0x0408816f,0x0001a693,0x0300cab8,0x0e07eddc,
  		0x2f1dfefb,0x5241f5fc,0x7362e2ec,0x8e80c9d6,0xa89bafbc,0xc3b594a1,0xe1d27e89,0xfff06673,}},
  		{0x10,'D',{
  		0x99b5858f,0x5f7c8883,0x28429c8f,0x010fc6ab,0x240cf4e1,0x5d41fefb,0x957af1fc,0xc1adcbe0,
  		0xd2cc92af,0xd3d25875,0xd7d71f3b,0xd7d71b02,0xd4d75538,0xd4d48f72,0xe1d9c9ac,0xffe6f4e6,}},
  		{0x10,'E',{
  		0x391c948f,0x73569595,0xad908a92,0xddc8677e,0xf1ee304d,0xc3dd0d1b,0x89a70002,0x536d1304,
  		0x233b3a25,0x08137053,0x0301aa8d,0x220edcc6,0x573af7ee,0x9174fffc,0xcaaef6ff,0xffe5dbeb,}},
  		{0x10,'G',{
  		0xaaca0000,0x698a0000,0x2a491106,0x000f4226,0x23067061,0x64437674,0xa3836874,0xdac04759,
  		0xfaec0b2a,0xfefb401f,0xffff8160,0xf5fdc0a1,0xc9e9eedf,0x89a9fff9,0x4869faff,0x0928e3f3,}},	
  		{0x10,'G',{
  		0xeaff1421,0xb9d20308,0x88a00000,0x57700f05,0x2b3f2618,0x09174d37,0x00037f66,0x0d05af97,
  		0x2a1adac7,0x5940ede5,0x8b72f2f3,0xbca4e9ee,0xe4d2cbde,0xfbf09cb3,0xf5f8ceb5,0xe9f1ffe6,}},
  		{0x10,'H',{
  		0x03021300,0x06053a26,0x0b0a604d,0x0b0b8774,0x0a0bae9a,0x0506d4c1,0x0002fbe8,0x1104e0f0,
  		0x2e1ec3d1,0x503dadb5,0x7764a5a7,0x9e8aa1a2,0xc4b1a3a0,0xead8ada8,0xfff8d1bd,0xfffff8e4,}},
  		{0x10,'K',{
  		0x1d1a2000,0x171a6040,0x1114a080,0x060edfc0,0x1100e2ff,0x3420a8c5,0x6f4f8b95,0xaf8f8285,
  		0xefcf8683,0xe1fcb3a0,0xa0c1c2bb,0x6080c6c5,0x2c40c9c7,0x6c4cd8d1,0xac8ceadf,0xedccfef3,}},
  		{0x10,'K',{
  		0x22341900,0x15185436,0x0e119072,0x0c0cccae,0x0709f6ea,0x0a07b9d8,0x2918859e,0x5b406170,
  		0x90796658,0x627c8b7c,0x2a47a79a,0x110db8b1,0x4d2fbfbc,0x896bcac4,0xc3a6d9d1,0xffe1ede2,}},
  		{0x10,'L',{
  		0x3f4a0c00,0x35372c1c,0x2c314d3d,0x26296e5d,0x1b218e7e,0x1316af9f,0x0910cfc0,0x0004f1e0,
  		0x1605ffff,0x3727ffff,0x5848ffff,0x7a69fdff,0x9b8afcfd,0xbcabfcfc,0xddcdfafb,0xffeef9f9,}},
  		{0x10,'M',{
  		0x0900e0ff,0x2017a0c0,0x3a296381,0x4e442443,0x5a583010,0x6b5f6f4f,0x7471ae8f,0x7977eece,
  		0x8c80c5e5,0xa19886a5,0xbaad4766,0xd3c70a29,0xddda3516,0xe7e17555,0xf4f0b494,0xfffaf4d4,}},
  		{0x10,'M',{
  		0x0e00421a,0x1414936a,0x1416e3bb,0x1813c0e8,0x201b6f97,0x2f261e47,0x664d2c09,0x7a737c54,
  		0x7c7bcda5,0x7e7accf5,0x8b847ba4,0x9c932b53,0xd5b30d09,0xece25d35,0xfaf5ae85,0xfffdffd6,}},	
  		{0x10,'M'+0x100,{
  		0xf1ffe0ff,0xdce8a2c0,0xc8d16282,0xbbc12343,0xaab22a0b,0x9fa46a4a,0x9298a989,0x808ae8c9,
  		0x6f74bfde,0x61697f9f,0x555b4060,0x464f0120,0x363d3f1f,0x282f7e5e,0x151fbc9e,0x000afcdc,}},
  		{0x10,'N',{
  		0x0400e7ff,0x130bb8cf,0x281e89a1,0x38305a71,0x51452c43,0x675d1d13,0x68684e36,0x6b697f66,
  		0x726fb097,0x7875e0c8,0x907ee8f8,0xa79ebbd2,0xbfb38fa4,0xd1c95f77,0xe6da3148,0xfff20019,}},
  		{0x0c,'O',{
  		0x2e3f311f,0x101e5c46,0x03088f76,0x0001c2a8,0x1e08e7da,0x4f35fdf4,0x8168fcff,0xb39beef5,
  		0xdac7cedf,0xf3e9a0b8,0xfef96d87,0xf9ff3c54,0xdaec1326,0xaac30108,0x77900100,0x465e1407,}},
  		{0x0c,'O',{
  		0x8670020b,0xb8a01307,0xe3ce3423,0xf8f0664c,0xfffc9b81,0xf1faceb5,0xcee4f4e5,0x9ab4fffb,
  		0x657fffff,0x364ceaf8,0x1623c0d7,0x00098ea7,0x06015973,0x24122e41,0x4d380c1c,0x82670104,}},
  		{0x0c,'O',{
  		0xd0e30213,0x9cb60000,0x68820c05,0x384f2416,0x17254c36,0x040c8066,0x0001b49a,0x1305e4ce,
  		0x442bfaf0,0x785efffe,0xab92f1f9,0xd3c1cfe3,0xf1e3a1b9,0xfffa6e88,0xf8ff3b54,0xd5e81024,}},
  	 	{0x0c,'O',{
  	 	0x000f768a,0x0900455d,0x2b171e30,0x5a420611,0x8d740100,0xbca5170b,0xe3d23824,0xfcf2644c,
  		0xfaff977e,0xe3f0c4af,0xbdd2e6d7,0x8ea7faf2,0x5b74fefe,0x2e44e9f6,0x0a1bc2d6,0x02028fa9,}},
  		{0x0c,'O',{
  		0x040e8a71,0x0b03bca4,0x2c19e7d4,0x5d43fef5,0x9077f9fe,0xbea8deee,0xdfcfb6cb,0xf7ed859f,
  		0xfefd516b,0xe6f62237,0xb7d00812,0x839d0002,0x4f690701,0x20371f11,0x040e4e34,0x00028268,}},
  		{0x0c,'O',{
  		0x829c0900,0x4e682315,0x24384a34,0x08157c61,0x0002b598,0x0d03edd1,0x4326fffd,0x7a5feef8,
  		0xab93cfe0,0xd5c1a7bd,0xf4e67690,0xfbff3d5a,0xcfec1b26,0x96b31818,0x5e7a251d,0x28433b2f,}},
  		{0x0c,'O',{
  		0x381e5e68,0x6e535156,0xa388504f,0xd8be5e56,0xf9ed876d,0xf9fcbaa1,0xd8ece5d2,0xa5c0f9f2,
  		0x708bfffd,0x3b55fbfe,0x1423d7ed,0x0006a4bf,0x09027089,0x26154157,0x50391e2e,0x7e670010,}},	
  		{0x10,'Q',{
  		0xc9e4020f,0x8dab0000,0x516f0802,0x18341f11,0x02065537,0x35186f68,0x71536b6f,0xaa8e5963,	
  		0xdec53a4b,0xfef40924,0xe1ef3e24,0xc0d07157,0xabb4ac8e,0x9da4e8ca,0xc5aaeffd,0xfde0d6e2,}},
  		{0x10,'S',{
  		0xb7cf0001,0x869e0301,0x556d0905,0x273e1f12,0x0311442c,0x2009665a,0x5138726b,0x826a7876,
  		0xb39b807b,0xdfcb998b,0xfff5bea7,0xdcf2ded0,0xadc6f1e8,0x7c94fbf7,0x4b63fffd,0x1932ffff,}},
  		{0x10,'S',{
  		0xcbde0200,0xa8ba1209,0x8597241a,0x6a753f2f,0x806c5751,0xa6935e5b,0xccb96662,0xf2e0746b,
  		0xfcff9482,0xe0f0b2a6,0xbdcfc2bb,0x97abd1c9,0x7385ddd7,0x4c60e8e3,0x273af4ee,0x0014fff9,}},
  		{0x10,'U',{
  		0x050d2209,0x0001573c,0x03008c71,0x1106bfa6,0x2f1bebda,0x604ae1f0,0x8873bccd,0xa59990a8,
  		0xbcb05f78,0xcdc72c46,0xd0d00911,0xc9cb3e24,0xc6c87359,0xc9c6a88d,0xd8d2ddc2,0xffe4fff6,}},
  		{0x10,'V',{
  		0x09000f00,0x1911301f,0x27205240,0x342d7563,0x413a9785,0x4f47b9a8,0x6057d9c9,0x7569f9ea,
  		0x9486f4ff,0xa99fd5e5,0xb8b0b4c5,0xc9c093a3,0xdbd17484,0xe9e35263,0xf5ef2f41,0xfff90b1d,}},
  		{0x10,'V',{
  		0x07008274,0x170f9d90,0x271fb6aa,0x382fd0c2,0x463febdd,0x534df7fa,0x635bdbe9,0x716ac1ce,
  		0x827aa7b4,0x928a8e9a,0xa39a7682,0xb6ac5e6a,0xc8bf4753,0xdad1303b,0xede41924,0xfff4000d,}},
  		{0x10,'W',{
  		0x06001f00,0x110c5f3f,0x1c189f7f,0x2822debe,0x4131e3fd,0x554ba4c3,0x655c6484,0x786f2444,
  		0x847f2f0f,0x8a866f4f,0x928eae8f,0x9e99eece,0xbaacd0ee,0xd5c893b3,0xebe05373,0xfff61333,}},
  		{0x10,'W',{
  		0x0c00240b,0x2015563d,0x332b8970,0x4b416b84,0x5b533851,0x6a63061f,0x78722d14,0x817c5f46,
  		0x8b869279,0x9791c4ab,0xa39ef7de,0xb6aed5ee,0xc6bea2bb,0xd8cf7089,0xede33d56,0xfff60a24,}},
  		{0x10,'W',{
  		0x0d003219,0x1e15654b,0x2c24987e,0x3732cbb1,0x453dfee4,0x564dcde7,0x675d9bb4,0x7b706882,
  		0x9084354f,0xa39b021c,0xada83117,0xbab2644a,0xc8c0977d,0xded47791,0xf1e7445e,0xfff7112b,}},
  		{0x10,'W',{
  		0x00002d0b,0x0001714f,0x0902b593,0x2816f3d4,0x5844d4f1,0x796997b6,0x8a845375,0x858a0f31,
  		0x7f804a28,0x7e7e8e6c,0x8a82d2b0,0xb596fcf4,0xe4d0cae7,0xfcf489ab,0xfffe4567,0xf9fd0023,}},
  	 	{0x10,'W'+0x100,{
  	 	0xf7ff2000,0xe4ed6040,0xd5dba181,0xbdcbe0c0,0xa0aad3f3,0x909892b3,0x848a5272,0x80811131,
  	 	0x777d3d1d,0x636d7e5e,0x535bbf9e,0x3c48fdde,0x272fc1e2,0x121a82a2,0x030a4161,0x00020021,}},
  		{0x10,'Y',{
  		0x16000b13,0x442d0303,0x4b48341b,0x61505e4b,0x91795c62,0xbca74551,0xe1d02637,0xfcf40c14,
  		0xe8f13922,0xdbe16951,0xd6d99a82,0xced3cbb2,0xb0c4f0e1,0x7f98fbf7,0x4e67fefd,0x1d36fdff,}},
  		{0x10,'Z',{
  		0x30160200,0x644a0403,0x997f0303,0xcdb30202,0xe7e80d00,0xc4d63622,0x9bb05c4a,0x73857f6c,
  		0x5061a893,0x293eccbb,0x0013f2dd,0x2d13fcfd,0x6248f6f8,0x967cf1f3,0xcbb1edef,0xffe5f1ec,}},
  		{0x10,'<',{
  		0xf0ff0b00,0xd1e11c14,0xb0c02c24,0x90a13c33,0x71804c44,0x51605c54,0x2f406d64,0x0d1e7c75,
  		0x16058d86,0x38279b94,0x5747a9a2,0x7768b9b1,0x9686c9c0,0xb5a6dad1,0xd5c6ece3,0xf5e4fff6,}},
  		{0x10,'>',{
  		0x17070600,0x3928160f,0x5949271f,0x796a372f,0x9a8a483f,0xb9aa5951,0xd8c86b62,0xfae97e74,
  		0xe3f48d85,0xc1d29c95,0x9fb0aca4,0x7e8ebab3,0x5d6dcbc2,0x3c4cdbd3,0x1f2dece4,0x0010fff5,}},
  		//--------------------------------------------------------------------------------------------
  		{0x10,0x1001,{
  		0x0003ecff,0x0502c6d9,0x0b099fb2,0x1410788c,0x221b5265,0x362b2f40,0x5341121d,0x7966020a,
  		0xa08d0100,0xc3b3170b,0xd9ce3a28,0xede25f4d,0xf4f28672,0xfaf6ac99,0xfffdd3c0,0xfffffae6,}},
  		{0x10,0x1002,{
  		0x1900847d,0x4c328785,0x7f658b88,0xb198898b,0xe3cb7f88,0xf8f24f68,0xecf81d35,0xbfd9010b,
  		0x90a61504,0x8186462d,0x7c7d7960,0x7f7bac93,0x8883dfc6,0xaf97fff4,0xdcc7eafa,0xffeec1d7,}},
  		{0x10,0x1003,{
  		0x7543141a,0xd7a82e17,0xf8f78f5c,0xc6e6e9bf,0x6497f8fa,0x1338b3db,0x03024f82,0x4a1c0620,
  		0xaf7c1001,0xf8da582b,0xeafebc8b,0x9acbfbe6,0x3868eeff,0x0a1892c4,0x2712305f,0x85520e11,}},
  		{0x10,0x1004,{
  		0x04003204,0x120b8e60,0x1714ebbd,0x2f27b8e6,0x43385b89,0x5b4c032d,0x6a666032,0x7770bc8e,
  		0x8c82b8e6,0x9b945c8a,0xaea2012d,0xbbb75d2f,0xc9c1ba8c,0xe3d5bce7,0xf1ea5f8d,0xfff50231,}},
  		{0x10,0x1005,{
  		0x1900020a,0x4d330400,0x7c65180a,0xa18f3f2b,0xb3ac7258,0xbcb8a58b,0xb0b9d7bf,0x8aa0fcec,
  		0x5971f2fd,0x414bc2db,0x433f8ea8,0x534a5d76,0x71613246,0x9d85101e,0xd0b60609,0xffea1409,}},
  		{0x10,0x1006,{
  		0xdeff0714,0x9abc0002,0x57790a02,0x1d373018,0x01076d4b,0x2f0f988a,0x72519c9c,0xb2948b9c,
  		0xa3bc576b,0x60815653,0x26417963,0x020eb191,0x2005e7d3,0x6442fbf4,0xa785fbff,0xebc9e7f3,}},
  		{0x10,0x1007,{
  		0xf6ff0600,0xe4ed140c,0xd5dd261d,0xc5cd362e,0xb3bc463e,0xa2aa574e,0x939a6860,0x83897970,
  		0x747c8a82,0x646c9c93,0x525baca4,0x434abdb4,0x333bcfc6,0x222addd5,0x121beee6,0x0009fff6,}},
  		{0x10,0x1008,{
  		0x09000900,0x19111b13,0x28202d24,0x39303d35,0x49424e45,0x5a515d56,0x6b626d65,0x7d747b74,
  		0x8e868b82,0x9d969c93,0xaca4aea5,0xbcb4bfb6,0xcac4d1c7,0xdbd2e1d9,0xece3f1e9,0xfff5fff8,}},
  		{0x10,0x1009,{
  		0x0a00faff,0x1d14edf4,0x2e25dce5,0x3e36cbd4,0x4e44bac2,0x5f57aab2,0x6f679aa2,0x7f778890,
  		0x8c85757e,0x9c94636b,0xaba3515a,0xbbb2414a,0xcbc33039,0xddd31f28,0xeee51119,0xfff7000a,}},
  		{0x10,0x100a,{
  		0xf4fffaff,0xe1eaeff6,0xd1d9dde6,0xc1cacdd5,0xb4bbbac3,0xa2aca8b0,0x929a99a1,0x83888791,
  		0x767d747d,0x666e636b,0x535c545e,0x444d424b,0x333d323a,0x242b212a,0x141c0f18,0x000a0008,}},
  		{0x10,0x100b,{
  		0x30000208,0x90600200,0xf1c11e0c,0xb5e64d3f,0x55855653,0x32245556,0x93625756,0xf1c3745e,
  		0xbaeaa997,0x598ab2b0,0x0f29aab1,0x7040a8a7,0xd1a0b8ae,0xd0f8ecd0,0x6f9ffcf5,0x0e3ffcff,}},
  		{0x10,0x100c,{
  		0x2600140c,0x66494226,0x827c8d66,0x6d80d8b4,0x284ffaf4,0x0a0ab9e0,0x411f8097,0x8e689182,
  		0xd6b47f94,0xf9f23960,0xd5f80012,0x91af270a,0x7e83734c,0x7e7dc19a,0xb490fae5,0xffdbe9fe,}},
  		{0x10,0x100d,{
  		0x768e0c00,0x465e2619,0x192f4635,0x0107745a,0x32178a85,0x674d858a,0x9b81747d,0xccb45c69,
  		0xf7e33b4d,0xebfd0d21,0xb6d00004,0x939e270d,0x888d5d42,0x83859378,0x7c80c9ae,0x6c75ffe4,}},	
  //		{0x10,0x100e,{
  //		0xb3bd1000,0x9ea82d1e,0x87924a3b,0x6f7b6658,0x56628375,0x3e4a9e91,0x2934bcad,0x1720ddcd,
  //		0x010bfced,0x2513ffff,0x4937fdff,0x6d5bf9fa,0x9280f4f7,0xb6a4f0f1,0xdac8eeef,0xffececed,}},
  };
  #endif
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  static void SortBubble(int t[],int size)
  {
  	int temp = 0;
  	int m,n;
  	for(m=0;m<size;m++)
  	{
  		for(n=m+1;n<size;n++)
  		{
  			temp = t[m];
  			if (temp>t[n])
  			{
  				t[m] = t[n];
  				t[n] = temp;
  			}
  		}
  	}
  }
  
  static int Sqrt(int d)
  {
  	int ret = 0;
  	int i;
  	for(i=14;i>=0;i--)
  	{
  		if((ret + (0x1<<i))*(ret + (0x1<<i)) <= d)
  			ret |= (0x1<<i);
  	}
  	return ret;
  }
  
  static UINT PointRange(int x0,int y0,int x1,int y1)
  {
  	if(x0 < 1)//&& x1>=1
  	{
  		if(x0 != x1)
  			y0 = y1 + (y0 - y1)*(1 - x1)/(x0 - x1);
  		x0 = 1;
  	}
  	if(x0 >= (int)drv_num_nokey*64)
  	{
  		if(x0 != x1)
  			y0 = y1 + (y0 - y1)*((int)drv_num_nokey*64 - x1)/(x0 - x1);
  		x0 = drv_num_nokey*64-1;
  	}
  	if(y0 < 1)
  	{
  		if(y0 != y1)
  			x0 = x1 + (x0 - x1)*(1 - y1)/(y0 - y1);
  		y0 = 1;
  	}
  	if(y0 >= (int)sen_num_nokey*64)
  	{
  		if(y0 != y1)
  			x0 = x1 + (x0 - x1)*((int)sen_num_nokey*64 - y1)/(y0 - y1);
  		y0 = sen_num_nokey*64-1;
  	}
  	if(x0 < 1)
  		x0 = 1;
  	if(x0 >= (int)drv_num_nokey*64)
  		x0 = drv_num_nokey*64-1;
  	if(y0 < 1)
  		y0 = 1;
  	if(y0 >= (int)sen_num_nokey*64)
  		y0 = sen_num_nokey*64-1;
  	return (x0 <<16)+ y0;
  }
  
  static void PointCoor(void)
  {
  	int i;
  	point_num &= 0xff;
  	for(i=0;i<point_num;i++)
  	{
  		if(global_state.ex)
  			point_now[i].all &= (FLAG_COOR_EX | FLAG_KEY | FLAG_ABLE);
  		else
  			point_now[i].all &= (FLAG_COOR | FLAG_KEY | FLAG_ABLE);
  	}
  }
  static void PointRepeat(void)
  {
  	int i,j;
  	int x,y;
  	int x_min,x_max,y_min,y_max;
  	int pn;
  	if(point_near)
  		point_near --;
  	if(prev_num > point_num)
  		point_near = 8;
  	if(point_repeat[0]==0 || point_repeat[1]==0)
  	{
  		if(point_near)
  			pn = 96;
  		else
  			pn = 32;
  	}
  	else
  	{
  		if(point_near)
  			pn = point_repeat[1];
  		else
  			pn = point_repeat[0];
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(point_now[i].all == 0)
  			continue;
  		if(point_now[i].key)
  			continue;
  		x_min = point_now[i].x - pn;
  		x_max = point_now[i].x + pn;
  		y_min = point_now[i].y - pn;
  		y_max = point_now[i].y + pn;
  		for(j=i+1;j<POINT_MAX;j++)
  		{
  			if(point_now[j].all == 0)
  				continue;
  			if(point_now[j].key)
  				continue;
  			x = point_now[j].x;
  			y = point_now[j].y;
  			if(x>x_min && x<x_max && y>y_min && y<y_max)
  			{
  				point_now[i].x = (point_now[i].x + point_now[j].x + 1) / 2;
  				point_now[i].y = (point_now[i].y + point_now[j].y + 1) / 2;
  				point_now[j].all = 0;
  				i--;
  				point_near = 8;
  				break;
  			}
  		}
  	}
  }
  
  static void PointPointer(void)
  {
  	int i,pn;
  	point_n ++ ;
  	if(point_n >= PP_DEEP * PS_DEEP * PR_DEEP * PRESSURE_DEEP)
  		point_n = 0;
  	pn = point_n % PP_DEEP;
  	for(i=0;i<PP_DEEP;i++)
  	{
  		pp[i] = point_array[pn];
  		if(pn == 0)
  			pn = PP_DEEP - 1;
  		else
  			pn--;
  	}
  	pn = point_n % PS_DEEP;
  	for(i=0;i<PS_DEEP;i++)
  	{
  		ps[i] = point_array[pn+PP_DEEP];
  		if(pn == 0)
  			pn = PS_DEEP - 1;
  		else
  			pn--;
  	}
  	pn = point_n % PR_DEEP;
  	for(i=0;i<PR_DEEP;i++)
  	{
  		pr[i] = point_array[pn+PP_DEEP+PS_DEEP];
  		if(pn == 0)
  			pn = PR_DEEP - 1;
  		else
  			pn--;
  	}
  	pn = point_n % PRESSURE_DEEP;
  	for(i=0;i<PRESSURE_DEEP;i++)
  	{
  		pa[i] = pressure_array[pn];
  		if(pn == 0)
  			pn = PRESSURE_DEEP - 1;
  		else
  			pn--;
  	}
  	//-------------------------------------------------------------------------
  	pn = 0;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(point_now[i].all)
  			point_now[pn++].all = point_now[i].all;
  		pp[0][i].all = 0;
  		ps[0][i].all = 0;
  		pr[0][i].all = 0;
  	}
  	point_num = pn;
  	for(i=pn;i<POINT_MAX;i++)
  		point_now[i].all = 0;
  }
  
  static unsigned int CCO(unsigned int x,unsigned int coe[],int k)
  {
  	if(k == 0)
  	{
  		if(x & 32)
  			return (x & ~31)+(31 - (coe[31-(x&31)] & 31));
  		else
  			return (x & ~31)+(coe[x&31] & 31);
  	}
  	if(k == 1)
  	{
  		if(x & 64)
  			return (x & ~63)+(63 - (coe[63-(x&63)] & 63));
  		else
  			return (x & ~63)+(coe[x&63] & 63);
  	}
  	if(k == 2)
  	{
  		return (x & ~63)+(coe[x&63] & 63);
  	}
  	return 0;
  }
  
  static void CoordinateCorrect(void)
  {
  	typedef struct
  	{
  		unsigned int range;
  		unsigned int group; 
  	}MULTI_TYPE;
  #ifdef LINE_MULTI_SIZE
  	#define	LINE_SIZE	LINE_MULTI_SIZE
  #else
  	#define	LINE_SIZE		4
  #endif
  	int i,j;
  	unsigned int *px[LINE_SIZE+1],*py[LINE_SIZE+1];
  	MULTI_TYPE multi_x[LINE_SIZE],multi_y[LINE_SIZE];
  	unsigned int edge_size = 64;
  	int kx,ky;
  	if((coordinate_correct_able&0xf) == 0)
  		return;
  	kx = (coordinate_correct_able>>4)&0xf;
  	ky = (coordinate_correct_able>>8)&0xf;
  	px[0] = coordinate_correct_coe_x;
  	py[0] = coordinate_correct_coe_y;
  	for(i=0;i<LINE_SIZE;i++)
  	{
  		px[i+1] = NULL;
  		py[i+1] = NULL;
  	}
  	if(kx == 3 || ky == 3)
  	{
  		i=0;
  		if(((coordinate_correct_able>>4)&0xf) == 3)
  			px[1] = multi_group[i++];
  		if(((coordinate_correct_able>>8)&0xf) == 3)
  			py[1] = multi_group[i++];
  	}
  	else
  	{
  		for(i=0;i<LINE_SIZE;i++)
  		{
  			multi_x[i].range = multi_x_array[i] & 0xffff;
  			multi_x[i].group = multi_x_array[i] >> 16;
  			multi_y[i].range = multi_y_array[i] & 0xffff;
  			multi_y[i].group = multi_y_array[i] >> 16;
  		}
  		j=1;
  		for(i=0;i<LINE_SIZE;i++)
  			if(multi_x[i].range && multi_x[i].group<LINE_SIZE)
  				px[j++] = multi_group[multi_x[i].group];
  		j=1;
  		for(i=0;i<LINE_SIZE;i++)
  			if(multi_y[i].range && multi_y[i].group<LINE_SIZE)
  				py[j++] = multi_group[multi_y[i].group];
  	}
  	for(i=0;i<(int)point_num && i<POINT_MAX;i++)
  	{
  		if(point_now[i].all==0)
  			break;
  		if(point_now[i].key!=0)
  			continue;
  		if(point_now[i].x >= edge_size && point_now[i].x <= drv_num_nokey*64 - edge_size)
  		{
  			if(kx == 3)
  			{
  				if(point_now[i].x & 64)
  					point_now[i].x = CCO(point_now[i].x,px[0],2);
  				else
  					point_now[i].x = CCO(point_now[i].x,px[1],2);
  			}
  			else
  			{
  				for(j=0;j<LINE_SIZE+1;j++)
  				{
  					if(!(j>=LINE_SIZE || px[j+1] == NULL || multi_x[j].range == 0 || point_now[i].x < multi_x[j].range))
  						continue;
  					point_now[i].x = CCO(point_now[i].x,px[j],kx);
  					break;
  				}
  			}
  		}
  		if(point_now[i].y >= edge_size && point_now[i].y <= sen_num_nokey*64 - edge_size)
  		{
  			if(ky == 3)
  			{
  				if(point_now[i].y & 64)
  					point_now[i].y = CCO(point_now[i].y,py[0],2);
  				else
  					point_now[i].y = CCO(point_now[i].y,py[1],2);
  			}
  			else
  			{
  				for(j=0;j<LINE_SIZE+1;j++)
  				{
  					if(!(j>=LINE_SIZE || py[j+1] == NULL || multi_y[j].range == 0 || point_now[i].y < multi_y[j].range))
  						continue;
  					point_now[i].y = CCO(point_now[i].y,py[j],ky);
  					break;
  				}
  			}
  		}
  	}
  #undef LINE_SIZE
  }
  
  static void PointPredictOne(unsigned int n)
  {
  	pp[0][n].all = pp[1][n].all & FLAG_COOR;
  	pp[0][n].predict = 0;
  }
  
  static void PointPredictTwo(unsigned int n)
  {
  	int x,y;
  	x = pp[1][n].x * 2 - pp[2][n].x;
  	y = pp[1][n].y * 2 - pp[2][n].y;
  	pp[0][n].all = PointRange(x,y,pp[1][n].x,pp[1][n].y);
   	pp[0][n].predict = 1;
  }
  
  static void PointPredictThree(unsigned int n)
  {
  	int x,y;
  	x = pp[1][n].x * 5 + pp[3][n].x - pp[2][n].x * 4;
  	x /= 2;
  	y = pp[1][n].y * 5 + pp[3][n].y - pp[2][n].y * 4;
  	y /= 2;
  	pp[0][n].all = PointRange(x,y,pp[1][n].x,pp[1][n].y);
  	pp[0][n].predict = 1;
  }
  
  static void PointPredict(void)
  {
  	int i;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pp[1][i].all != 0)
  		{
  			if(global_state.interpolation 
  				|| pp[2][i].all  == 0 
  				|| pp[2][i].fill != 0 
  				|| pp[3][i].fill != 0 
  				|| pp[1][i].key  != 0
  				|| global_state.only)
  			{
  				PointPredictOne(i);
  			}
  			else if(pp[2][i].all != 0)
  			{
  				if(pp[3][i].all != 0)
  					PointPredictThree(i);
  				else
  					PointPredictTwo(i);
  			}
  			pp[0][i].all |= FLAG_FILL;
  			pa[0][i] = pa[1][i];
  		}
  		else
  			pp[0][i].all = 0x0fff0fff;
  		if(pp[1][i].key)
  			pp[0][i].all |= FLAG_KEY;
  	}
  }
  
  static unsigned int PointDistance(gsl_POINT_TYPE *p1,gsl_POINT_TYPE *p2)
  {
  	int a,b,ret;
  	a = p1->dis.x;
  	b = p2->dis.x;
  	ret = (a-b)*(a-b);
  	a = p1->dis.y;
  	b = p2->dis.y;
  	ret += (a-b)*(a-b);
  	return ret;
  }
  
  static void DistanceInit(gsl_DISTANCE_TYPE *p)
  {
  	int i;
  	unsigned int *p_int = &(p->d[0][0]);
  	for(i=0;i<POINT_MAX*POINT_MAX;i++)
  		*p_int++ = 0x7fffffff;
  }
  
  static int DistanceMin(gsl_DISTANCE_TYPE *p)
  {
  	int i,j;
  	p->min = 0x7fffffff;
  	for(j=0;j<POINT_MAX;j++)
  	{
  		for(i=0;i<POINT_MAX;i++)
  		{
  			if(p->d[j][i] < p->min)
  			{
  				p->i = i;
  				p->j = j;
  				p->min = p->d[j][i];
  			}
  		}
  	}
  	if(p->min == 0x7fffffff)
  		return 0;
  	return 1;
  }
  
  static void DistanceIgnore(gsl_DISTANCE_TYPE *p)
  {
  	int i,j;
  	for(i=0;i<POINT_MAX;i++)
  		p->d[p->j][i] = 0x7fffffff;
  	for(j=0;j<POINT_MAX;j++)
  		p->d[j][p->i] = 0x7fffffff;
  }
  
  static int SpeedGet(int d)
  {
  	int i;
  	for(i=8;i>0;i--)
  	{
  		if(d > 0x100<<i)
  			break;
  	}
  	return i;
  }
  
  static void PointId(void)
  {
  	int i,j;
  	gsl_DISTANCE_TYPE distance;
  	unsigned int id_speed[POINT_MAX];
  	DistanceInit(&distance);
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pp[0][i].predict == 0 || pp[1][i].fill != 0)
  			id_speed[i] = id_first_coe;
  		else
  			id_speed[i] = SpeedGet( PointDistance(&pp[1][i],&pp[0][i]) );
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pp[0][i].all == FLAG_COOR)
  			continue;
  		for(j=0;j<point_num && j<POINT_MAX;j++)
  		{
  			distance.d[j][i] = PointDistance(&point_now[j],&pp[0][i]);
  		}
  	}
  	if(point_num == 0)
  		return;
  	if(global_state.only)
  	{
  		do
  		{
  			if(DistanceMin(&distance))
  			{
  				if(pp[1][0].all!=0 && pp[1][0].key != point_now[distance.j].key)
  				{
  					DistanceIgnore(&distance);
  					continue;
  				}
  				pp[0][0].all = point_now[distance.j].all;
  			}
  			else
  				pp[0][0].all = point_now[0].all;
  			for(i=0;i<POINT_MAX;i++)
  				point_now[i].all = 0;
  		}
  		while(0);
  		point_num = 1;
  	}
  	else
  	{
  		for(j=0;j<point_num && j<POINT_MAX;j++)
  		{
  			if(DistanceMin(&distance) == 0)
  				break;
  			if(distance.min >= (id_static_coe + id_speed[distance.i] * id_speed_coe) /**average/(soft_average+1)*/)
  			{
  				//point_now[distance.j].id = 0xf;//new id
  				continue;
  			}
  			pp[0][distance.i].all = point_now[distance.j].all;
  			pa[0][distance.i] = pressure_now[distance.j];
  			point_now[distance.j].all = 0;
  			DistanceIgnore(&distance);
  		}
  	}
  }
  
  static int ClearLenPP(int i)
  {
  	int n;
  	for(n=0;n<PP_DEEP;n++)
  	{
  		if(pp[n][i].all)
  			break;
  	}
  	return n;
  }
  static void PointNewId(void)
  {
  	int id,j;
  	for(j=0;j<POINT_MAX;j++)
  		if((pp[0][j].all & FLAG_COOR) == FLAG_COOR)
  			pp[0][j].all = 0;
  	for(j=0;j<POINT_MAX;j++)
  	{
  		if(point_now[j].all != 0)
  		{
  			if(point_now[j].able)
  				continue;
  			for(id=1;id<=POINT_MAX;id++)
  			{
  				if(ClearLenPP(id-1) > (int)(1+1))
  				{
  					pp[0][id-1].all = point_now[j].all;
  					pa[0][id-1] = pressure_now[j];
  					point_now[j].all = 0;
  					break;
  				}
  			}
  		}
  	}
  }
  
  static void PointOrder(void)
  {
  	int i;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pp[0][i].fill == 0)
  			continue;
  		if(pp[1][i].all==0 || pp[1][i].fill!=0 || filter_able==0 || filter_able==1)
  		{
  			pp[0][i].all = 0;
  			pressure_now[i] = 0;
  		}
  	}
  }
  
  static void PointCross(void)
  {
  	unsigned int i,j;
  	unsigned int t;
  	for(j=0;j<POINT_MAX;j++)
  	{
  		for(i=j+1;i<POINT_MAX;i++)
  		{
  			if(pp[0][i].all == 0 || pp[0][j].all == 0
  			|| pp[1][i].all == 0 || pp[1][j].all == 0)
  				continue;
  			if(((pp[0][j].x < pp[0][i].x && pp[1][j].x > pp[1][i].x)
  			 || (pp[0][j].x > pp[0][i].x && pp[1][j].x < pp[1][i].x))
  			&& ((pp[0][j].y < pp[0][i].y && pp[1][j].y > pp[1][i].y)
  			 || (pp[0][j].y > pp[0][i].y && pp[1][j].y < pp[1][i].y)))
  			{
  				t = pp[0][i].x;
  				pp[0][i].x = pp[0][j].x;
  				pp[0][j].x = t;
  				t = pp[0][i].y;
  				pp[0][i].y = pp[0][j].y;
  				pp[0][j].y = t;
  			}
  		}
  	}
  }
  
  static void GetPointNum(gsl_POINT_TYPE *pt)
  {
  	int i;
  	point_num = 0;
  	for(i=0;i<POINT_MAX;i++)
  		if(pt[i].all != 0)
  			point_num++;
  }
  
  static void PointDelay(void)
  {
  	int i,j;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(report_delay == 0)
  		{
  			point_delay[i].all = 0;
  			if(pp[0][i].all)
  				point_delay[i].able = 1;
  			continue;
  		}
  		if(pp[0][i].all!=0 && point_delay[i].init == 0 && point_delay[i].able == 0)
  		{
  			if(point_num == 0)
  				continue;
  			point_delay[i].delay  = (report_delay >> 3*((point_num>10?10:point_num)-1))&0x7;
  			point_delay[i].report = (report_ahead >> 3*((point_num>10?10:point_num)-1))&0x7;
  			if(point_delay[i].report > point_delay[i].delay)
  				point_delay[i].report = point_delay[i].delay;
  			point_delay[i].init = 1;
  		}
  		if(pp[0][i].all == 0)
  		{
  			point_delay[i].init = 0;
  		}
  		if(point_delay[i].able == 0 && point_delay[i].init != 0)
  		{
  			for(j=0;j<=(int)point_delay[i].delay;j++)
  				if(pp[j][i].all == 0 || pp[j][i].fill != 0 || pp[j][i].able!=0)
  					break;
  			if(j <= (int)point_delay[i].delay)
  				continue;
  			point_delay[i].able = 1;
  		}
  		if(pp[point_delay[i].report][i].all == 0)
  		{
  			point_delay[i].able = 0;
  			continue;
  		}
  		if(point_delay[i].able == 0)
  			continue;
  		if(point_delay[i].report)
  		{
  			if(PointDistance(&pp[point_delay[i].report][i],&pp[point_delay[i].report-1][i]) < 3*3)
  				point_delay[i].report --;
  		}
  	}
  }
  
  static void FilterOne(int i,int *ps_c,int *pr_c,int denominator)
  {
  	int j;
  	int x=0,y=0;
  	pr[0][i].all = ps[0][i].all;
  	if(pr[0][i].all == 0)
  		return;
  	if(denominator <= 0)
  		return;
  	for(j=0;j<8;j++)
  	{
  		x += (int)pr[j][i].x * (int)pr_c[j] + (int)ps[j][i].x * (int)ps_c[j];
  		y += (int)pr[j][i].y * (int)pr_c[j] + (int)ps[j][i].y * (int)ps_c[j];
  	}
  	x = (x + denominator/2) / denominator;
  	y = (y + denominator/2) / denominator;
  	if(x < 0)
  		x = 0;
  	if(x > 0xffff)
  		x = 0xffff;
  	if(y < 0)
  		y = 0;
  	if(y > 0xfff)
  		y = 0xfff;
  	pr[0][i].x = x;
  	pr[0][i].y = y;
  }
  
  static unsigned int FilterSpeed(int i)
  {
  	return (Sqrt(PointDistance(&ps[0][i],&ps[1][i])) + Sqrt(PointDistance(&ps[1][i],&ps[2][i])))/2;
  }
  
  static int MedianSpeedOver(int id,int deep)
  {
  	int i;
  	unsigned int dis;
  	int speed_over = 0;
  	deep = deep/2 - 1;
  	if(deep < 0 || deep > 3)
  		return TRUE;
  	dis = median_dis[deep] * median_dis[deep];
  	for(i=0;i<=deep && i<POINT_DEEP;i++)
  	{
  		if(PointDistance(&ps[i][id],&ps[i+1][id]) > dis)
  			speed_over ++;
  	}
  	if(speed_over >= 2)
  		return TRUE;
  	return FALSE;
  }
  
  static void PointMedian(void)
  {
  	int i,j;
  	int deep;
  	int buf_x[PS_DEEP],buf_y[PS_DEEP];
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(filter_deep[i] < 3)
  			deep = 3;
  		else
  			deep = filter_deep[i] + 2;
  		if(deep >= PS_DEEP)
  			deep = PS_DEEP-1;
  		deep |= 1;
  		for(;deep>=3;deep-=2)
  		{
  			if(MedianSpeedOver(i,deep))
  				continue;
  			for(j=0;j<deep;j++)
  			{
  				buf_x[j] = ps[j][i].x;
  				buf_y[j] = ps[j][i].y;
  			}
  			SortBubble(buf_x,deep);
  			SortBubble(buf_y,deep);
  			pr[0][i].x = buf_x[deep/2];
  			pr[0][i].y = buf_y[deep/2];
  		}
  		filter_deep[i] = deep;
  	}
  }
  static void PointFilter(void)
  {
  	int i,j;
  	int speed_now;
  	int filter_speed[6];
  	int ps_c[8];
  	int pr_c[8];
  	for(i=0;i<POINT_MAX;i++)
  	{
  		pr[0][i].all = ps[0][i].all;
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pr[0][i].all!=0 && pr[1][i].all == 0)
  		{
  			for(j=1;j<PR_DEEP;j++)
  				pr[j][i].all = ps[0][i].all;
  			for(j=1;j<PS_DEEP;j++)
  				ps[j][i].all = ps[0][i].all;
  		}
  	}
  	if(filter_able >=0 && filter_able <= 1)
  		return;
  	if(filter_able > 1)
  	{
  		for(i=0;i<8;i++)
  		{
  			ps_c[i] = (filter_coe[i/4] >> ((i%4)*8)) & 0xff;
  			pr_c[i] = (filter_coe[i/4+2] >> ((i%4)*8)) & 0xff;
  			if(ps_c[i] >= 0x80)
  				ps_c[i] |= 0xffffff00;
  			if(pr_c[i] >= 0x80)
  				pr_c[i] |= 0xffffff00;
  		}
  		for(i=0;i<POINT_MAX;i++)
  		{
  			FilterOne(i,ps_c,pr_c,filter_able);
  		}
  	}
  	else if(filter_able == -1)
  	{
  		PointMedian();
  	}
  	else if(filter_able < 0)
  	{
  		for(i=0;i<4;i++)
  			filter_speed[i+1] = median_dis[i];
  		filter_speed[0] = median_dis[0] * 2 - median_dis[1];
  		filter_speed[5] = median_dis[3] /2;
  		for(i=0;i<POINT_MAX;i++)
  		{
   			if(pr[0][i].all == 0)
  			{
  				filter_deep[i] = 0;
  				continue;
  			}
  			speed_now = FilterSpeed(i);
  			if(filter_deep[i] > 0 && speed_now > filter_speed[filter_deep[i]+1 - 2])
  				filter_deep[i] --;
  			else if(filter_deep[i] < 3 && speed_now < filter_speed[filter_deep[i]+1 + 2])
  				filter_deep[i] ++;
  				
  			FilterOne(i,ps_coe[filter_deep[i]],pr_coe[filter_deep[i]],0-filter_able);
  		}
  	}
  }
  static unsigned int KeyMap(int *drv,int *sen)
  {
  	typedef struct
  	{
  		unsigned int up_down,left_right;
  		unsigned int coor;
  	}KEY_TYPE_RANGE;
  	KEY_TYPE_RANGE *key_range = (KEY_TYPE_RANGE * )key_range_array;
  	int i;
  	for(i=0;i<8;i++)
  	{
  		if((unsigned int)*drv >= (key_range[i].up_down >> 16) 
  		&& (unsigned int)*drv <= (key_range[i].up_down & 0xffff)
  		&& (unsigned int)*sen >= (key_range[i].left_right >> 16)
  		&& (unsigned int)*sen <= (key_range[i].left_right & 0xffff))
  		{
  			*sen = key_range[i].coor >> 16;
  			*drv = key_range[i].coor & 0xffff;
  			return key_range[i].coor;
  		}
  	}
  	return 0;
  }
  
  static unsigned int ScreenResolution(gsl_POINT_TYPE *p)
  {
  	int x,y;
  	x = p->x;
  	y = p->y;
  	if(p->key == FALSE)
  	{
  		y = ((y - match_y[1]) * match_y[0] + 2048)/4096;
  		x = ((x - match_x[1]) * match_x[0] + 2048)/4096 ;
  	}
  	y = y * (int)screen_y_max / ((int)sen_num_nokey * 64);
  	x = x * (int)screen_x_max / ((int)drv_num_nokey * 64);
  	if(p->key == FALSE)
  	{
  		if((ignore_y[0]!=0 || ignore_y[1]!=0))
  		{
  			if(y < ignore_y[0])
  				return 0;
  			if(ignore_y[1] <= screen_y_max/2 && y > screen_y_max - ignore_y[1])
  				return 0;
  			if(ignore_y[1] >= screen_y_max/2 && y > ignore_y[1])
  				return 0;
  		}
  		if(ignore_x[0]!=0 || ignore_x[1]!=0)
  		{
  			if(x < ignore_x[0])
  				return 0;
  			if(ignore_x[1] <= screen_y_max/2 && x > screen_x_max - ignore_x[1])
  				return 0;
  			if(ignore_x[1] >= screen_y_max/2 && x > ignore_x[1])
  				return 0;
  		}
  		if(y <= (int)edge_cut[2])
  			y = (int)edge_cut[2] + 1;
  		if(y >= screen_y_max - (int)edge_cut[3])
  			y = screen_y_max - (int)edge_cut[3] - 1;
  		if(x <= (int)edge_cut[0])
  			x = (int)edge_cut[0] + 1;
  		if(x >= screen_x_max - (int)edge_cut[1])
  			x = screen_x_max - (int)edge_cut[1] - 1;
  		if(global_flag.opposite_x)
  			y = screen_y_max - y;
  		if(global_flag.opposite_y)
  			x = screen_x_max - x;
  		if(global_flag.opposite_xy)
  		{
  			y ^= x;
  			x ^= y;
  			y ^= x;
  		}
  	}
  	else
  	{
  		if(y < 0)
  			y = 0;
  		if(x < 0)
  			x = 0;
  		if((key_map_able & 0x1) != FALSE && KeyMap(&x,&y) == 0)
  			return 0;
  	}
  	return ((y<<16) & 0x0fff0000) + (x & 0x0000ffff);
  }
  
  static void PointReport(struct gsl_touch_info *cinfo)
  {
  	int i;
  	unsigned int data[POINT_MAX];
  	int num = 0;
  	if(point_num > point_num_max && global_flag.over_report_mask != 0)
  	{
  		point_num = 0;
  		cinfo->finger_num = 0;	
  		return;
  	}
  	for(i=0;i<POINT_MAX;i++)
  		data[i] = 0;
  	num = 0;
  	if(global_flag.id_over)
  	{
  		for(i=0;i<POINT_MAX && num<point_num_max;i++)
  		{
  			if(point_delay[i].able == 0)
  				continue;
  			if(point_delay[i].report >= PR_DEEP-1)
  				continue;
  			if(pr[point_delay[i].report+1][i].able == 0)
  				continue;
  			if(pr[point_delay[i].report][i].all)
  			{
  				pr[point_delay[i].report][i].able = 1;
  				data[i] = ScreenResolution(&pr[point_delay[i].report][i]);
  				if(data[i])
  				{
  					data[i] |= (i+1)<<28;
  					num++;
  				}
  			}
  		}
  		for(i=0;i<POINT_MAX && num<point_num_max;i++)
  		{
  			if(point_delay[i].able == 0)
  				continue;
  			if(point_delay[i].report >= PR_DEEP)
  				continue;
  			if(pr[point_delay[i].report][i].all == 0)
  				continue;
  			if(pr[point_delay[i].report][i].able == 0)
  			{
  				pr[point_delay[i].report][i].able = 1;
  				data[i] = ScreenResolution(&pr[point_delay[i].report][i]);
  				if(data[i])
  				{
  					data[i] |= (i+1)<<28;
  					num++;
  				}
  			}
  		}
  	}
  	else
  	{
  		num=0;
  		for(i=0;i<point_num_max && i<POINT_MAX;i++)
  		{
  			if(point_delay[i].able == 0)
  				continue;
  			if(point_delay[i].report >= PR_DEEP)
  				continue;
  			data[num] = ScreenResolution(&pr[point_delay[i].report][i]);
  			if(data[num])
  				data[num++] |= (i+1)<<28;
  		}
  	}
  	num = 0;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(data[i] == 0)
  			continue;
  		point_now[num].all = data[i];
  		cinfo->x[num] = (data[i] >> 16) & 0xfff;
  		cinfo->y[num] = data[i] & 0xfff;
  		cinfo->id[num] = data[i] >> 28; 
  		pressure_now[num] = pressure_report[i];
  		num ++; 
  	}
  	for(i=num;i<POINT_MAX;i++)
  	{
  		point_now[i].all = 0;
  		pressure_now[i] = 0;
  	}
  	point_num = num;
  	cinfo->finger_num = num;
  }
  
  
  
  static void PointEdge(void)
  {
  	typedef struct
  	{
  		int range;
  		int coe;
  	}STRETCH_TYPE;
  	typedef struct
  	{
  		STRETCH_TYPE up[4];
  		STRETCH_TYPE down[4];
  		STRETCH_TYPE left[4];
  		STRETCH_TYPE right[4];
  	}STRETCH_TYPE_ALL;
  	STRETCH_TYPE_ALL *stretch;
  	int i,id;
  	int data[2];
  	int x,y;
  	int sac[4*4*2];
  	if(screen_x_max == 0 || screen_y_max == 0)
  		return;
  	id = 0;
  	for(i=0;i<4*4*2;i++)
  	{
  		sac[i] = stretch_array[i];
  		if(sac[i])
  			id++;
  	}
  	if(id == 0)
  		return;
  	stretch = (STRETCH_TYPE_ALL *)sac;
  	for(i=0;i<4;i++)
  	{
  		if(stretch->right[i].range > screen_y_max * 64 / 128
  		|| stretch->down [i].range > screen_x_max * 64 / 128)
  		{
  			for(i=0;i<4;i++)
  			{
  				if(stretch->up[i].range)
  					stretch->up[i].range = stretch->up[i].range * drv_num_nokey * 64 / screen_x_max;
  				if(stretch->down[i].range)
  					stretch->down[i].range = (screen_x_max - stretch->down[i].range) * drv_num_nokey * 64 / screen_x_max;
  				if(stretch->left[i].range)
  					stretch->left[i].range = stretch->left[i].range * sen_num_nokey * 64 / screen_y_max;
  				if(stretch->right[i].range)
  					stretch->right[i].range = (screen_y_max - stretch->right[i].range) * sen_num_nokey * 64 / screen_y_max;
  			}
  			break;
  		}
  	}
  	for(id=0;id<POINT_MAX;id++)
  	{
  		if(point_now[id].all == 0 || point_now[id].key!=0)
  			continue;
  		x = point_now[id].x;
  		y = point_now[id].y;
  
  		data[0] = 0;
  		data[1] = y;
  		for(i=0;i<4;i++)
  		{
  			if(stretch->left[i].range == 0)
  				break;
  			if(data[1] < stretch->left[i].range)
  			{
  				data[0] += (stretch->left[i].range - data[1]) * stretch->left[i].coe/128;
  				data[1] = stretch->left[i].range;
  			}
  		}
  		y = data[1] - data[0];
  		if(y <= 0)
  			y = 1;
  		if(y >= (int)sen_num_nokey*64)
  			y = sen_num_nokey*64 - 1;
  
  		data[0] = 0;
  		data[1] = sen_num_nokey * 64 - y;
  		for(i=0;i<4;i++)
  		{
  			if(stretch->right[i].range == 0)
  				break;
  			if(data[1] < stretch->right[i].range)
  			{
  				data[0] += (stretch->right[i].range - data[1]) * stretch->right[i].coe/128;
  				data[1] = stretch->right[i].range;
  			}
  		}
  		y = sen_num_nokey * 64 - (data[1] - data[0]);
  		if(y <= 0)
  			y = 1;
  		if(y >= (int)sen_num_nokey*64)
  			y = sen_num_nokey*64 - 1;
  
  		data[0] = 0;
  		data[1] = x;
  		for(i=0;i<4;i++)
  		{
  			if(stretch->up[i].range == 0)
  				break;
  			if(data[1] < stretch->up[i].range)
  			{
  				data[0] += (stretch->up[i].range - data[1]) * stretch->up[i].coe/128;
  				data[1] = stretch->up[i].range;
  			}
  		}
  		x = data[1] - data[0];
  		if(x <= 0)
  			x = 1;
  		if(x >= (int)drv_num_nokey*64)
  			x = drv_num_nokey*64 - 1;
  
  		data[0] = 0;
  		data[1] = drv_num_nokey * 64 - x;
  		for(i=0;i<4;i++)
  		{
  			if(stretch->down[i].range == 0)
  				break;
  			if(data[1] < stretch->down[i].range)
  			{
  				data[0] += (stretch->down[i].range - data[1]) * stretch->down[i].coe/128;
  				data[1] = stretch->down[i].range;
  			}
  		}
  		x = drv_num_nokey * 64 - (data[1] - data[0]);
  		if(x <= 0)
  			x = 1;
  		if(x >= (int)drv_num_nokey*64)
  			x = drv_num_nokey*64 - 1;
  
  		point_now[id].x = x;
  		point_now[id].y = y;
  	}
  }
  
  static void PointStretch(void)
  {
  	static int save_dr[POINT_MAX],save_dn[POINT_MAX];
  	typedef struct  
  	{
  		int dis;
  		int coe;
  	}SHAKE_TYPE;
  	SHAKE_TYPE * shake_all = (SHAKE_TYPE *) shake_all_array;
  	int i,j;
  	int dn;
  	int dr;
  	int dc[9],ds[9];
  	int len = 8;
  	unsigned int temp;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		ps[0][i].all = pp[0][i].all;
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pp[0][i].all == 0 || pp[0][i].key)
  		{
  			point_shake &= ~(0x1<<i);
  			if(i == 0)
  				point_edge.rate = 0;
  			continue;
  		}
  		if(i == 0)
  		{
  			if(edge_first!=0 && ps[1][i].all == 0)
  			{
  				point_edge.coor.all = ps[0][i].all;
  				if(point_edge.coor.x < (unsigned int)		((edge_first>>24) & 0xff))
  					point_edge.coor.x =						((edge_first>>24) & 0xff);
  				if(point_edge.coor.x > drv_num_nokey*64 -	((edge_first>>16) & 0xff))
  					point_edge.coor.x = drv_num_nokey*64 -	((edge_first>>16) & 0xff);
  				if(point_edge.coor.y < (unsigned int)		((edge_first>> 8) & 0xff))
  					point_edge.coor.y =						((edge_first>> 8) & 0xff);
  				if(point_edge.coor.y > sen_num_nokey*64 -	((edge_first>> 0) & 0xff))
  					point_edge.coor.y = sen_num_nokey*64 -	((edge_first>> 0) & 0xff);
  				if(point_edge.coor.all != ps[0][i].all)
  				{
  					point_edge.dis = PointDistance(&ps[0][i],&point_edge.coor);
  					if(point_edge.dis)
  						point_edge.rate = 0x1000;
  				}
  			}
  			if(point_edge.rate!=0 && point_edge.dis!=0)
  			{
  				temp = PointDistance(&ps[0][i],&point_edge.coor);
  				if(temp >= point_edge.dis * edge_first_coe / 0x80)
  				{
  					point_edge.rate = 0;
  				}
  				else if(temp > point_edge.dis)
  				{
  					temp = (point_edge.dis *  edge_first_coe / 0x80 - temp)*0x1000/point_edge.dis;
  					if(temp < point_edge.rate)
  						point_edge.rate = temp;
  				}
  				ps[0][i].x = point_edge.coor.x + (ps[0][i].x - point_edge.coor.x)*(0x1000 - point_edge.rate)/0x1000;
  				ps[0][i].y = point_edge.coor.y + (ps[0][i].y - point_edge.coor.y)*(0x1000 - point_edge.rate)/0x1000;
  			}
  		}
  		if(ps[1][i].all == 0)
  		{
  			continue;
  		}
  		else if((point_shake & (0x1<<i)) == 0)
  		{
  			if(PointDistance(&ps[0][i],&ps[1][i]) < (unsigned int)shake_min)
  			{
  				ps[0][i].all = ps[1][i].all;
  				continue;
  			}
  			else
  				point_shake |= (0x1<<i);
  		}
  	}
  	for(i=0;i<len;i++)
  	{
  		if(shake_all[i].dis == 0)
  		{
  			len=i;
  			break;
  		}
  	}
  	if(len == 1)
  	{
  		ds[0] = shake_all[0].dis;
  		dc[0] = (shake_all[0].coe*100+64)/128;
  		for(i=0;i<POINT_MAX;i++)
  		{
  			if(ps[1][i].all == 0)
  			{
  				for(j=1;j<PS_DEEP;j++)
  					ps[j][i].all = ps[0][i].all;
  				continue;
  			}
  			if((point_shake & (0x1<<i)) == 0)
  				continue;
  			dn = PointDistance(&pp[0][i],&ps[1][i]);
  			dn = Sqrt(dn);
  			dr = dn>ds[0] ? dn-ds[0] : 0;
  			temp = ps[0][i].all;
  			if(dn == 0 || dr == 0)
  			{
  				ps[0][i].x = ps[1][i].x;
  				ps[0][i].y = ps[1][i].y;
  			}
  			else
  			{
  				ps[0][i].x = (int)ps[1][i].x + ((int)pp[0][i].x - (int)ps[1][i].x) * dr / dn;
  				ps[0][i].y = (int)ps[1][i].y + ((int)pp[0][i].y - (int)ps[1][i].y) * dr / dn;
  			}
  			if(dc[0] > 0)
  			{
  				if(ps[0][i].all == ps[1][i].all && temp != ps[0][i].all)
  				{
  					ps[0][i].all = temp;
  					point_decimal[i].x += ps[0][i].x - ps[1][i].x;
  					point_decimal[i].y += ps[0][i].y - ps[1][i].y;
  					ps[0][i].x = ps[1][i].x;
  					ps[0][i].y = ps[1][i].y;
  					if(point_decimal[i].x >  dc[0] && ps[1][i].x < 0xffff)
  					{
  						ps[0][i].x += 1;
  						point_decimal[i].x = 0;
  					}
  					if(point_decimal[i].x  < -dc[0] && ps[1][i].x > 0)
  					{
  						ps[0][i].x -= 1;
  						point_decimal[i].x = 0;
  					}
  					if(point_decimal[i].y >  dc[0] && ps[1][i].y < 0xffff)
  					{
  						ps[0][i].y += 1;
  						point_decimal[i].y = 0;
  					}
  					if(point_decimal[i].y  < -dc[0] && ps[1][i].y > 0)
  					{
  						ps[0][i].y -= 1;
  						point_decimal[i].y = 0;
  					}
  				}
  				else
  				{
  					point_decimal[i].x = 0;
  					point_decimal[i].y = 0;
  				}
  			}
  		}
  		
  	}
  	else if(len >= 2)
  	{
  		for(i=0;i<8 && i<len;i++)
  		{
  			ds[i+1] = shake_all[i].dis;
  			dc[i+1] = shake_all[i].coe;//;ds[i+1] * shake_all[i].coe;
  		}
  		if(shake_all[0].coe >= 128 || shake_all[0].coe <= shake_all[1].coe)
  		{
  			ds[0] = ds[1];
  			dc[0] = dc[1];
  		}
  		else
  		{
  			ds[0] = ds[1] + (128 - shake_all[0].coe)*(ds[1]-ds[2])/(shake_all[0].coe - shake_all[1].coe);
  			dc[0] = 128;
  		}
  		for(i=0;i<POINT_MAX;i++)
  		{
  			if(ps[1][i].all == 0)
  			{
  				for(j=1;j<PS_DEEP;j++)
  					ps[j][i].all = ps[0][i].all;
  				save_dr[i] = 128;
  				save_dn[i] = 0;
  				continue;
  			}
  			if((point_shake & (0x1<<i)) == 0)
  				continue;
  			dn = PointDistance(&pp[0][i],&ps[1][i]);
  			dn = Sqrt(dn);
  			if(dn >= ds[0])
  			{
  				continue;
  			}
  			if(dn < save_dn[i])
  			{
  				dr = save_dr[i];
  				save_dn[i] = dn;
  				ps[0][i].x = (int)ps[1][i].x + (((int)pp[0][i].x - (int)ps[1][i].x) * dr) / 128;
  				ps[0][i].y = (int)ps[1][i].y + (((int)pp[0][i].y - (int)ps[1][i].y) * dr) / 128;
  				continue;
  			}
  			for(j=0;j<=len;j++)
  			{
  				if(j == len || dn == 0)
  				{
  					ps[0][i].x = ps[1][i].x;
  					ps[0][i].y = ps[1][i].y;
  					break;
  				}
  				else if(ds[j] > dn && dn >=ds[j+1])
  				{
  					dr = dc[j+1] + ((dn - ds[j+1]) * (dc[j] - dc[j+1])) / (ds[j] - ds[j+1]);
  					save_dr[i] = dr;
  					save_dn[i] = dn;
  //					ps[0][i].x = (int)ps[1][i].x + ((int)pp[0][i].x - (int)ps[1][i].x) * dr / dn / 128;
  //					ps[0][i].y = (int)ps[1][i].y + ((int)pp[0][i].y - (int)ps[1][i].y) * dr / dn / 128;
  					ps[0][i].x = (int)ps[1][i].x + (((int)pp[0][i].x - (int)ps[1][i].x) * dr+64) / 128;
  					ps[0][i].y = (int)ps[1][i].y + (((int)pp[0][i].y - (int)ps[1][i].y) * dr+64) / 128;
  					break;
  				}
  			}
  		}
  	}
  	else
  	{
  		return;
  	}
  }
  
  static void ResetMask(void)
  {
  	if(reset_mask_send)
  	{
  		reset_mask_send = 0;
  	}
  	if(global_state.mask)
  		return;
  	if(reset_mask_dis ==0 || reset_mask_type == 0)
  		return;
  	if(reset_mask_max == 0xfffffff1)
  	{
  		if(point_num == 0) 
  			reset_mask_max = 0xf0000000 + 1;
  		return;
  	}
  	if(reset_mask_max >  0xf0000000)
  	{
  		reset_mask_max --;
  		if(reset_mask_max == 0xf0000000)
  		{
  			reset_mask_send = reset_mask_type;
  			global_state.mask = 1;
  		}
  		return;
  	}
  	if(point_num > 1 || pp[0][0].all == 0)
  	{
  		reset_mask_count = 0;
  		reset_mask_max = 0;
  		reset_mask_count = 0;
  		return;
  	}
  	reset_mask_count ++;
  	if(reset_mask_max == 0)
  		reset_mask_max = pp[0][0].all;
  	else 
  		if(PointDistance((gsl_POINT_TYPE*)(&reset_mask_max),pp[0]) > (((unsigned int)reset_mask_dis) & 0xffffff)
  		&& reset_mask_count > (((unsigned int)reset_mask_dis) >> 24))
  			reset_mask_max = 0xfffffff1;
  }
  
  static int ConfigCoorMulti(int data[])
  {
  	int i,j;
  	int n = 0;
  	for(i=0;i<4;i++)
  	{
  		if(data[247+i]!=0)
  		{
  			if((data[247+i]&63)==0 && (data[247+i]>>16)<4)
  				n++;
  			else
  				return FALSE;
  		}
  		if(data[251+i]!=0)
  		{
  			if((data[251+i]&63)==0 && (data[251+i]>>16)<4)
  				n++;
  			else
  				return FALSE;
  		}
  	}
  	if(n == 0 || n > 4)
  		return FALSE;
  	for(j=0;j<n;j++)
  	{
  		for(i=0;i<64;i++)
  		{
  			if(data[256+j*64+i] >= 64)
  				return FALSE;
  			if(i)
  			{
  				if(data[256+j*64+i] < data[256+j*64+i-1])
  					return FALSE;
  			}
  		}
  	}
  	return TRUE;
  }
  
  static int ConfigFilter(unsigned int data[])
  {
  	int i;
  	unsigned int ps_c[8];
  	unsigned int pr_c[8];
  	unsigned int sum = 0;
  	if(data[242]>1 && (data[255]>=0 && data[255]<=256))
  	{
  		for(i=0;i<8;i++)
  		{
  			ps_c[i] = (data[243+i/4] >> ((i%4)*8)) & 0xff;
  			pr_c[i] = (data[243+i/4+2] >> ((i%4)*8)) & 0xff;
  			if(ps_c[i] >= 0x80)
  				ps_c[i] |= 0xffffff00;
  			if(pr_c[i] >= 0x80)
  				pr_c[i] |= 0xffffff00;
  			sum += ps_c[i];
  			sum += pr_c[i];
  		}
  		if(sum == data[242] || sum + data[242] == 0)
  			return TRUE;
  	}
  	return FALSE;
  }
  
  static int ConfigKeyMap(int data[])
  {
  	int i;
  	if(data[217] != 1)
  		return FALSE;
  	for(i=0;i<8;i++)
  	{
  		if(data[218+2] == 0)
  			return FALSE;
  		if((data[218+i*3+0]>>16) > (data[218+i*3+0]&0xffff))
  			return FALSE;
  		if((data[218+i*3+1]>>16) > (data[218+i*3+1]&0xffff))
  			return FALSE;
  	}
  	return TRUE;
  }
  
  static int DiagonalDistance(gsl_POINT_TYPE *p,int type)
  {
  	int divisor,square;
  	divisor = ((int)sen_num_nokey * (int)sen_num_nokey + (int)drv_num_nokey * (int)drv_num_nokey)/16;
  	if(divisor == 0)
  		divisor = 1;
  	if(type == 0)
  		square = ((int)sen_num_nokey*(int)(p->x) - (int)drv_num_nokey*(int)(p->y)) / 4;
  	else
  		square = ((int)sen_num_nokey*(int)(p->x) + (int)drv_num_nokey*(int)(p->y) - (int)sen_num_nokey*(int)drv_num_nokey*64) / 4;
  	return square * square / divisor;
  }
  
  static void DiagonalCompress(gsl_POINT_TYPE *p,int type,int dis,int dis_max)
  {
  	int x,y;
  	int tx,ty;
  	int cp_ceof;
  	if(dis_max == 0)
  		return;
  	if(dis > dis_max)
  		cp_ceof = (dis - dis_max)*128/(3*dis_max) + 128;
  	else
  		cp_ceof = 128;
  	if(cp_ceof > 256)
  		cp_ceof = 256;
  	x = p->x;
  	y = p->y;
  	if(type)
  		y = (int)sen_num_nokey*64 - y;
  	x *= (int)sen_num_nokey;
  	y *= (int)drv_num_nokey;
  	tx = x;
  	ty = y;
  	x = ((tx+ty)+(tx-ty)*cp_ceof/256)/2;
  	y = ((tx+ty)+(ty-tx)*cp_ceof/256)/2;
  	x /= (int)sen_num_nokey;
  	y /= (int)drv_num_nokey;
  	if(type)
  		y = sen_num_nokey*64 - y;
  	if(x < 1)
  		x = 1;
  	if(y < 1)
  		y = 1;
  	if(x >= (int)drv_num_nokey*64)
  		x = drv_num_nokey*64 - 1;
  	if(y >= (int)sen_num_nokey*64)
  		y = (int)sen_num_nokey*64 - 1;
  	p->x = x;
  	p->y = y;
  }
  
  static void PointDiagonal(void)
  {
  	int i;
  	int diagonal_size;
  	int dis;
  	unsigned int diagonal_start;
  	if(diagonal == 0)
  		return;
  	diagonal_size = diagonal * diagonal;
  	diagonal_start = diagonal * 3/2;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(ps[0][i].all == 0 || ps[0][i].key != 0)
  		{
  			point_corner &= ~(0x3<<i*2);
  			continue;
  		}
  		else if((point_corner & (0x3<<i*2)) == 0)
  		{
  			if((ps[0][i].x <= diagonal_start && ps[0][i].y <= diagonal_start)
  			|| (ps[0][i].x >= drv_num_nokey*64 - diagonal_start && ps[0][i].y >= sen_num_nokey*64 - diagonal_start))
  				point_corner |= 0x2<<i*2;
  			else if((ps[0][i].x <= diagonal_start && ps[0][i].y >= sen_num_nokey*64 - diagonal_start)
  			|| (ps[0][i].x >= drv_num_nokey*64 - diagonal_start && ps[0][i].y <= diagonal_start))
  				point_corner |= 0x3<<i*2;
  			else
  				point_corner |= 0x1<<i*2;
  		}
  		if(point_corner & (0x2<<i*2))
  		{
  			dis = DiagonalDistance(&(ps[0][i]),point_corner & (0x1<<i*2));
  			if(dis <= diagonal_size*4)
  			{
  				DiagonalCompress(&(ps[0][i]),point_corner & (0x1<<i*2),dis,diagonal_size);
  			}
  			else if(dis > diagonal_size*4)
  			{
  				point_corner &= ~(0x3<<i*2);
  				point_corner |= 0x1<<i*2;
  			}
  		}
  	}
  }
  
  
  static int PointSlope(int i,int j)
  {
  	int x,y;
  	x = pr[j][i].x - pr[j+1][i].x;
  	x = x*x;
  	y = pr[j][i].y - pr[j+1][i].y;
  	y = y*y;
  	if(x+y == 0)
  		return -1;
  	if(x > y)
  		return x*1024/(x+y);
  	else
  		return y*1024/(x+y);
  }
  
  static void PointExtend(void)
  {
  	int i,j;
  	int x,y;
  	int t,t2;
  	int extend_len = 5;
  	if(point_extend == 0)
  		return;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pr[0][i].fill == 0)
  			continue;
  		for(j=0;j<extend_len;j++)
  		{
  			if(pr[j][i].all == 0)
  				break;
  		}
  		if(j < extend_len)
  			continue;
  		if(PointDistance(&pr[1][i],&pr[2][i]) < 16*16)
  			continue;
  		t = PointSlope(i,1);
  		for(j=2;j<extend_len-1;j++)
  		{
  			t2 = PointSlope(i,j);
  			if(t2 < 0 || t2 < t*(128-point_extend)/128 || t2 > t*(128+point_extend)/128)
  				break;
  		}
  		if(j<extend_len-1)
  			continue;
  		x = 3*pr[1][i].x - 2*pr[2][i].x;
  		y = 3*pr[1][i].y - 2*pr[2][i].y;
  		pr[0][i].all = PointRange(x,y,pr[1][i].x,pr[1][i].y);
  	}
  }
  
  static void PressureSave(void)
  {
  	int i;
  	if((point_num & 0x1000)==0)
  	{
  		return;
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		pressure_now[i] = point_now[i].all >> 28;
  		point_now[i].all &= ~(0xf<<28);
  	}
  }
  
  static void PointPressure(void)
  {
  	int i,j;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(pa[0][i]!=0 && pa[1][i]==0)
  		{
  			pressure_report[i] = pa[0][i]*5;
  			for(j=1;j<PRESSURE_DEEP;j++)
  				pa[j][i] = pa[0][i];
  			continue;
  		}
  		j = (pressure_report[i]+1)/2 + pa[0][i] + pa[1][i] + (pa[2][i]+1)/2 - pressure_report[i];
  		if(j >= 2)
  			j -= 2;
  		else if(j <= -2)
  			j += 2;
  		else
  			j = 0;
  		pressure_report[i] = pressure_report[i]+j;
  	}
  }
  
  void gsl_ReportPressure(unsigned int *p)
  {
  	int i;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(i < point_num)
  		{
  			if(pressure_now[i] == 0)
  				p[i] = 0;
  			else if(pressure_now[i] <= 7)
  				p[i] = 1;
  			else if(pressure_now[i] > 63+7)
  				p[i] = 63;
  			else
  				p[i] = pressure_now[i] - 7;
  		}
  		else
  			p[i] = 0;
  	}
  }
  EXPORT_SYMBOL(gsl_ReportPressure);
  
  int  gsl_TouchNear(void)
  {
  		return 0;
  }
  EXPORT_SYMBOL(gsl_TouchNear);
  
  static void DoubleClick(void)
  {
  	int i;
  	unsigned int width[3];
  	double_click = 0;
  
  	if(point_num>=2 || (point_num==1 && pp[0][0].all==0) || pp[0][0].key)
  	{
  
  		for(i=0;i<sizeof(click_count)/sizeof(click_count[0]);i++)
  			click_count[i] = 0;
  		return;
  	}
  	if(point_num!=0 && prev_num==0)
  	{
  		for(i=sizeof(click_count)/sizeof(click_count[0])-1;i>0;i--)
  			click_count[i] = click_count[i-1];
  		click_count[0] = csensor_count;
  		for(i=sizeof(point_click)/sizeof(point_click[0])-1;i>1;i--)
  			point_click[i].all = point_click[i-2].all;
  		point_click[0].all = pp[0][0].all;
  		point_click[1].all = pp[0][0].all;
  	}
  	if(point_num!=0 && prev_num!=0)
  	{
  		if(PointDistance(&point_click[1],&pp[0][0]) > PointDistance(&point_click[1],&point_click[0]))
  			point_click[0].all = pp[0][0].all;
  	}
  	if(point_num==0 && prev_num!=0)
  	{
  		for(i=sizeof(click_count)/sizeof(click_count[0])-1;i>0;i--)
  			click_count[i] = click_count[i-1];
  		click_count[0] = csensor_count;
  		for(i=0;i<sizeof(click_count)/sizeof(click_count[0])-1;i++)
  			width[i] = (click_count[i] - click_count[i+1]) & 0xffff;
  		if(!(width[0]>=double_down*average && width[2]>=double_down*average && width[1]<=double_up*average))
  		{
  			return;
  		}
  		if(PointDistance(&point_click[0],&point_click[1]) > 64*64
  		|| PointDistance(&point_click[2],&point_click[3]) > 64*64
  		|| PointDistance(&point_click[1],&point_click[3]) > 128*128)
  		{
  			return;
  		}
  		for(i=0;i<sizeof(click_count)/sizeof(click_count[0]);i++)
  			click_count[i] = 0;//?point_click
  		double_click = '*';
  	}
  } 
  
  static void gsl_id_reg_init(int flag)
  {
  	int i,j;
  	for(j=0;j<POINT_DEEP;j++)
  		for(i=0;i<POINT_MAX;i++)
  			point_array[j][i].all = 0;	
  	for(j=0;j<PRESSURE_DEEP;j++)
  		for(i=0;i<POINT_MAX;i++)
  			pressure_array[j][i] = 0;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		point_delay[i].all = 0;
  		filter_deep[i] = 0;
  		point_decimal[i].all = 0;
  	}
  	point_edge.rate = 0;
  	point_n = 0;
  	if(flag)
  		point_num = 0;
  	prev_num = 0;
  	point_shake = 0;
  	reset_mask_send = 0;
  	reset_mask_max = 0;
  	reset_mask_count = 0;
  	point_near = 0;
  	point_corner = 0;	
  	global_state.all = 0;
  	double_click = 0;
  	inte_count = 0;
  	csensor_count = 0;
  #ifdef GESTURE_LICH
  	GestureInit();
  #endif
  }
  
  static int DataCheck(void)
  {
  	if(drv_num==0 || drv_num_nokey==0 || sen_num==0 || sen_num_nokey==0)
  		return 0;
  	if(screen_x_max==0 || screen_y_max==0)
  		return 0;
  	return 1;
  }
  
  void gsl_DataInit(unsigned int * conf_in)
  {
  	int i;
  	unsigned int *conf;
  	int len;
  	gsl_id_reg_init(1);
  	for(i=0;i<POINT_MAX;i++)
  		point_now[i].all = 0;
  	conf = config_static;
  	coordinate_correct_able = 0;
  	for(i=0;i<32;i++)
  	{
  		coordinate_correct_coe_x[i] = i;
  		coordinate_correct_coe_y[i] = i;
  	}
  	id_first_coe = 8;
  	id_speed_coe = 128*128;
  	id_static_coe = 64*64;
  	average = 3+1;
  	soft_average = 3;
  	report_delay=0;
  	report_ahead = 0x9249249;
  	for(i=0;i<4;i++)
  		median_dis[i]=0;
  	shake_min = 0*0;
  	for(i=0;i<2;i++)
  	{
  		match_y[i]=0;
  		match_x[i]=0;
  		ignore_y[i]=0;
  		ignore_x[i]=0;
  	}
  	match_y[0]=4096;
  	match_x[0]=4096;
  	screen_y_max = 480;
  	screen_x_max = 800;
  	point_num_max=10;
  	drv_num = 16;
  	sen_num = 10;
  	drv_num_nokey = 16;
  	sen_num_nokey = 10;
  	for(i=0;i<4;i++)
  		edge_cut[i] = 0;
  	for(i=0;i<32;i++)
  		stretch_array[i] = 0;
  	for(i=0;i<16;i++)
  		shake_all_array[i] = 0;
  	reset_mask_dis = 0;
  	reset_mask_type=0;
  	diagonal = 0;
  	point_extend = 0;
  	key_map_able = 0;
  	for(i=0;i<8*3;i++)
  		key_range_array[i] = 0;
  	filter_able = 0;
  	filter_coe[0] = ( 0<<6*4)+( 0<<6*3)+( 0<<6*2)+(40<<6*1)+(24<<6*0);
  	filter_coe[1] = ( 0<<6*4)+( 0<<6*3)+(16<<6*2)+(24<<6*1)+(24<<6*0);
  	filter_coe[2] = ( 0<<6*4)+(16<<6*3)+(24<<6*2)+(16<<6*1)+( 8<<6*0);
  	filter_coe[3] = ( 6<<6*4)+(16<<6*3)+(24<<6*2)+(12<<6*1)+( 6<<6*0);
  	for(i=0;i<4;i++)
  	{
  		multi_x_array[i]=0;
  		multi_y_array[i]=0;
  	}
  	point_repeat[0] = 32;
  	point_repeat[1] = 96;
  	edge_first = 0;
  	edge_first_coe = 0x80;
  	//----------------------------------------------
  	if(conf_in == NULL)
  	{
  		return;
  	}
  	if(conf_in[0] <= 0xfff)
  	{
  		if(ConfigCoorMulti(conf_in))
  			len = 512;
  		else if(ConfigFilter(conf_in))
  			len = 256;
  		else if(ConfigKeyMap(conf_in)) 
  			len = 241;
  		else
  			len = 215;
  	}
  	else if(conf_in[1] <= CONFIG_LENGTH)
  		len = conf_in[1];
  	else
  		len = CONFIG_LENGTH;
  	for(i=0;i<len;i++)
  		conf[i] = conf_in[i];
  	for(;i<CONFIG_LENGTH;i++)
  		conf[i] = 0;
  	if(conf_in[0] <= 0xfff)
  	{
  		coordinate_correct_able = conf[0];
  		drv_num = conf[1];
  		sen_num = conf[2];
  		drv_num_nokey = conf[3];
  		sen_num_nokey = conf[4];
  		id_first_coe = conf[5];
  		id_speed_coe = conf[6];
  		id_static_coe = conf[7];
  		average = conf[8];
  		soft_average = conf[9];
  
  		report_delay = conf[13];
  		shake_min = conf[14];
  		screen_y_max = conf[15];
  		screen_x_max = conf[16];
  		point_num_max = conf[17];
  		global_flag.all = conf[18];
  		for(i=0;i<4;i++)
  			median_dis[i] = conf[19+i];
  		for(i=0;i<2;i++)
  		{
  			match_y[i] = conf[23+i];
  			match_x[i] = conf[25+i];
  			ignore_y[i] = conf[27+i];
  			ignore_x[i] = conf[29+i];
  		}
  		for(i=0;i<64;i++)
  		{
  			coordinate_correct_coe_x[i] = conf[31+i];
  			coordinate_correct_coe_y[i] = conf[95+i];
  		}
  		for(i=0;i<4;i++)
  			edge_cut[i] = conf[159+i];
  		for(i=0;i<32;i++)
  			stretch_array[i] = conf[163+i];
  		for(i=0;i<16;i++)
  			shake_all_array[i] = conf[195+i];
  		reset_mask_dis = conf[213];
  		reset_mask_type = conf[214];
  		key_map_able = conf[217];
  		for(i=0;i<8*3;i++)
  			key_range_array[i] = conf[218+i];
  		filter_able = conf[242];
  		for(i=0;i<4;i++)
  			filter_coe[i] = conf[243+i];
  		for(i=0;i<4;i++)
  			multi_x_array[i] = conf[247+i];
  		for(i=0;i<4;i++)
  			multi_y_array[i] = conf[251+i];
  		diagonal = conf[255];
  		for(i=0;i<256;i++)
  			//multi_group[0][i] = conf[256+i];
  			*(multi_group[0]+i) = conf[256+i];
  		for(i=0;i<32;i++)
  		{
  			//ps_coe[0][i] = conf[256 + 64*3 + i];
  			//pr_coe[0][i] = conf[256 + 64*3 + i + 32];
  			*(ps_coe[0]+i) = conf[256 + 64*3 + i];
  			*(pr_coe[0]+i) = conf[256 + 64*3 + i + 32];
  		}
  		//-----------------------
  		near_set[0] = 0;
  		near_set[1] = 0;
  	}
  	else
  	{
  		global_flag.all = conf[0x10];
  		point_num_max = conf[0x11];
  		drv_num = conf[0x12]&0xffff;
  		sen_num = conf[0x12]>>16;
  		drv_num_nokey = conf[0x13]&0xffff;
  		sen_num_nokey = conf[0x13]>>16;
  		screen_x_max = conf[0x14]&0xffff;
  		screen_y_max = conf[0x14]>>16;
  		average = conf[0x15];
  		reset_mask_dis = conf[0x16];
  		reset_mask_type = conf[0x17];
  		point_repeat[0] = conf[0x18]>>16;
  		point_repeat[1] = conf[0x18]&0xffff;
  		//conf[0x19~0x1f]
  		near_set[0] = conf[0x19]>>16;
  		near_set[1] = conf[0x19]&0xffff;
  		diagonal = conf[0x1a];
  		point_extend = conf[0x1b];
  		//-------------------------
  		
  		id_first_coe = conf[0x20];
  		id_speed_coe = conf[0x21];
  		id_static_coe = conf[0x22];
  		match_y[0] = conf[0x23]>>16;
  		match_y[1] = conf[0x23]&0xffff;
  		match_x[0] = conf[0x24]>>16;
  		match_x[1] = conf[0x24]&0xffff;
  		ignore_y[0] = conf[0x25]>>16;
  		ignore_y[1] = conf[0x25]&0xffff;
  		ignore_x[0] = conf[0x26]>>16;
  		ignore_x[1] = conf[0x26]&0xffff;
  		edge_cut[0] = (conf[0x27]>>24) & 0xff;
  		edge_cut[1] = (conf[0x27]>>16) & 0xff;
  		edge_cut[2] = (conf[0x27]>> 8) & 0xff;
  		edge_cut[3] = (conf[0x27]>> 0) & 0xff;
  		report_delay = conf[0x28];
  		shake_min = conf[0x29];
  		for(i=0;i<16;i++)
  		{
  			stretch_array[i*2+0] = conf[0x2a+i] & 0xffff;
  			stretch_array[i*2+1] = conf[0x2a+i] >> 16;
  		}
  		for(i=0;i<8;i++)
  		{
  			shake_all_array[i*2+0] = conf[0x3a+i] & 0xffff;
  			shake_all_array[i*2+1] = conf[0x3a+i] >> 16;
  		}
  		report_ahead			= conf[0x42];
  // 		key_dead_time			= conf[0x43];
  // 		point_dead_time			= conf[0x44];
  // 		point_dead_time2		= conf[0x45];
  // 		point_dead_distance		= conf[0x46];
  // 		point_dead_distance2	= conf[0x47];
  		edge_first				= conf[0x48];
  		edge_first_coe			= conf[0x49];
  		//goto_test
  		
  		key_map_able = conf[0x60];
  		for(i=0;i<8*3;i++)
  			key_range_array[i] = conf[0x61+i];
  		
  		coordinate_correct_able = conf[0x100];
  		for(i=0;i<4;i++)
  		{
  			multi_x_array[i] = conf[0x101+i];	
  			multi_y_array[i] = conf[0x105+i];
  		}
  		for(i=0;i<64;i++)
  		{
  			coordinate_correct_coe_x[i] = (conf[0x109+i/4]>>(i%4*8)) & 0xff;
  			coordinate_correct_coe_y[i] = (conf[0x109+64/4+i/4]>>(i%4*8)) & 0xff;
  		}	
  		for(i=0;i<256;i++)
  		{
  			//multi_group[0][i] = (conf[0x109+64/4*2+i/4]>>(i%4*8)) & 0xff;
  			*(multi_group[0]+i) = (conf[0x109+64/4*2+i/4]>>(i%4*8)) & 0xff;
  		}
  
  		filter_able = conf[0x180];
  		for(i=0;i<4;i++)
  			filter_coe[i] = conf[0x181+i];
  		for(i=0;i<4;i++)
  			median_dis[i] = conf[0x185+i];
  		for(i=0;i<32;i++)
  		{
  			//ps_coe[0][i] = conf[0x189 + i];
  			//pr_coe[0][i] = conf[0x189 + i + 32];
  			*(ps_coe[0]+i) = conf[0x189 + i];
  			*(pr_coe[0]+i) = conf[0x189 + i + 32];
  		}
  #ifdef GESTURE_LICH
  		GestureSet(&conf[0x189 + 64]);
  #endif
  	}
  	//---------------------------------------------
  	if(average == 0)
  		average = 4;
  	for(i=0;i<8;i++)
  	{
  		if(shake_all_array[i*2] & 0x8000)
  			shake_all_array[i*2] = shake_all_array[i*2] & ~0x8000;
  		else
  			shake_all_array[i*2] = Sqrt(shake_all_array[i*2]);
  	}
  	for(i=0;i<2;i++)
  	{
  		if(match_x[i] & 0x8000)
  			match_x[i] |= 0xffff0000;
  		if(match_y[i] & 0x8000)
  			match_y[i] |= 0xffff0000;
  		if(ignore_x[i] & 0x8000)
  			ignore_x[i] |= 0xffff0000;
  		if(ignore_y[i] & 0x8000)
  			ignore_y[i] |= 0xffff0000;
  	}
  	for(i=0;i<CONFIG_LENGTH;i++)
  		config_static[i] = 0;
  }
  EXPORT_SYMBOL(gsl_DataInit);
  
  unsigned int gsl_version_id(void)
  {
  	return GSL_VERSION;
  }
  EXPORT_SYMBOL(gsl_version_id);
  
  unsigned int gsl_mask_tiaoping(void)
  {
  	return reset_mask_send;
  }
  EXPORT_SYMBOL(gsl_mask_tiaoping);
  
  
  static void GetFlag(void)
  {
  	int i = 0;
  	int num_save;
  	if((point_num &0x8000) != 0)//��־��չ
  	{
  		if((point_num&0xff000000) == 0x5a000000)
  			gesture_last = (point_num>>16) & 0xff;
  	}
  	if(((point_num & 0x100)!=0)
  	|| ((point_num & 0x200)!=0 && global_state.reset == 1))
  	{
  		gsl_id_reg_init(0);
  	}
  	if((point_num & 0x300) == 0)
  	{
  		global_state.reset = 1;
  	}
  	if(point_num & 0x400)
  		global_state.only = 1;
  	else
  		global_state.only = 0;
  	if(point_num & 0x2000)
  		global_state.interpolation = 0xf;
  	else if(global_state.interpolation)
  		global_state.interpolation --;
  	if(point_num & 0x4000)
  		global_state.ex = 1;
  	else
  		global_state.ex = 0;
  	inte_count ++;	
  	csensor_count = ((unsigned int)point_num)>>16;
  	num_save = point_num & 0xff;
  	if(num_save > POINT_MAX)
  		num_save = POINT_MAX;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(i >= num_save)
  			point_now[i].all = 0;
  	}
  	point_num = (point_num & (~0xff)) + num_save;
  }
  
  void gsl_FunIICRead(unsigned int (*fun) (unsigned int *,unsigned int,unsigned int))
  {
  	ReadIICInt = fun;
  }
  EXPORT_SYMBOL(gsl_FunIICRead);
  
  static int GestureJoint(void)
  {
  	unsigned int buf[128];
  	unsigned int len = 0;
  	unsigned int addr = 0;
  	unsigned int i;
  	
  	if((point_num &0x8000) == 0)
  		return FALSE;
  	if((point_num &0xff000000) != 0x5b000000)
  		return FALSE;
  	if(ReadIICInt == NULL)
  		return FALSE;
  	addr = point_now[0].all;
  	len = point_now[1].all;
  	if(len > 128)
  		len = 128;
  	ReadIICInt(buf,addr,len);
  	if(len < 8)
  	{
  		gesture_last = 0x7fffffff;
  		return TRUE;
  	}
  	for(i=0;i<POINT_MAX;i++)
  		point_now[i].all = 0;
  	GestureInit();
  	for(i=0;i<len+5;i++)
  	{
  		if(i<len)
  		{
  			point_num = 1;
  			point_now[0].all = buf[i];
  			if( buf[i] == 0 || (buf[i] & 0xe000b000) != 0)
  			{
  				GestureInit();
  				break;
  			}
  		}
  		else
  		{
  			point_num = 0;
  			point_now[0].all = 0;
  		}
  		PointCoor();
  		CoordinateCorrect();
  		PointEdge();
  		PointPointer();
  		PointPredict();
  		PointId();
  		PointNewId();
  		PointOrder();
  		PointStretch();
  		PointFilter();
  		GetPointNum(pr[0]);
  		if(i<len + 2)
  			GestureMain(&(pr[0][0].all),point_num);	
  	}
  	point_num = 0;
  	for(i=0;i<POINT_MAX;i++)
  		point_now[i].all = 0;
  	return TRUE;
  }
  void gsl_alg_id_main(struct gsl_touch_info *cinfo)
  {
  	int i;
  	point_num = cinfo->finger_num;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		point_now[i].all = (cinfo->id[i]<<28) | (cinfo->x[i]<<16) | cinfo->y[i];
  	}
  	
  	if(GestureJoint())
  	{
  		cinfo->finger_num = 0;
  		for(i=0;i<POINT_MAX;i++)
  		{
  			cinfo->id[i] = 0;
  			cinfo->x[i] = 0;
  			cinfo->y[i] = 0;
  		}
  		return;
  	}
  	GetFlag();
  	if(DataCheck() == 0)
  	{
  		point_num = 0;
  		cinfo->finger_num = 0;	
  		return;
  	}
  	PressureSave();
  	PointCoor();
  	CoordinateCorrect();
  	PointEdge();
  	PointRepeat();
  	GetPointNum(point_now);
  	PointPointer();
  	PointPredict();
  	PointId();
  	PointNewId();
  	PointOrder();
  	PointCross();
  	GetPointNum(pp[0]);
  	DoubleClick();
  	prev_num = point_num;
  	ResetMask();
  	PointStretch();
  	PointDiagonal();
   	PointFilter();
  	GetPointNum(pr[0]);
  #ifdef GESTURE_LICH
  	GestureMain(&(pr[0][0].all),point_num);	
  #endif
  	PointDelay();
  	PointExtend();
  	PointPressure();
  	PointReport(cinfo);
  }
  EXPORT_SYMBOL(gsl_alg_id_main);
  
  
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  #ifdef GESTURE_LICH
  
  int gsl_obtain_gesture(void)
  {
  	return GestureDeal();
  }
  EXPORT_SYMBOL(gsl_obtain_gesture);
  
  static int GestureMain(unsigned int data_coor[],unsigned int num)
  {
  	gesture_deal = FALSE;
  	if(gesture_dis_min == 0)
  		return FALSE;
  	gesture_multi = GestureMulti(data_coor);	
  	if(gesture_multi)
  	{
  		gesture_deal = GESTURE_DEAL;
  		return TRUE;
  	}
  	if(num == 0)
  	{
  		if(gesture_num == 0)
  			return FALSE;
  		if(gesture_num <= 8)
  		{
  			GestureInit();
  			return FALSE;
  		}
  		gesture_deal = GESTURE_ALL;
  		return TRUE;
  	}
  	else if(gesture_num < 0)
  	{
  		return FALSE;
  	}
  	else if(num == 1 && data_coor[0] != 0)
  	{
  		GesturePush((GESTURE_POINT_TYPE*) data_coor);
  		return FALSE;
  	}
  	else// if(num > 1)
  	{
  		gesture_num = -1;
  		return FALSE;
  	}
  	return TRUE;
  }
  
  static int GestureSqrt(int d)
  {
  	int ret = 0;
  	int i;
  	for(i=14;i>=0;i--)
  	{
  		if((ret + (0x1<<i))*(ret + (0x1<<i)) <= d)
  			ret |= (0x1<<i);
  	}
  	return ret;
  }
  
  static int GestureDistance(GESTURE_POINT_TYPE* d1,GESTURE_POINT_TYPE* d2,int sqrt_able)
  {
  	if(sqrt_able)
  		return GestureSqrt((d1->x-d2->x)*(d1->x-d2->x) + (d1->y-d2->y)*(d1->y-d2->y));
  	else
  		return (d1->x-d2->x)*(d1->x-d2->x) + (d1->y-d2->y)*(d1->y-d2->y);
  }
  
  static int GesturePush(GESTURE_POINT_TYPE* data)
  {
  	unsigned int data_i = data->all & 0xffff0fff;
  	if(gesture_num >= GESTURE_BUF_SIZE)
  		return FALSE;
  	if(gesture_flag & 0x2)//x
  		data_i = ((drv_num_nokey*64 - (data_i>>16)) <<16) + (data_i & 0xffff);
  	if(gesture_flag & 0x4)//y
  		data_i = (data_i & 0xffff0000) + ((sen_num_nokey*64 - (data_i & 0xffff)) & 0xffff);
  	if(gesture_flag & 0x8)//xy
  		data_i = ((data_i & 0xfff)<<16) + ((data_i >> 16) & 0xfff);
  	if(gesture_num == 0)
  	{
  		gesture_buf[gesture_num ++].all = data_i;
  		return TRUE;
  	}
  	if(GestureDistance(data,&gesture_buf[gesture_num-1],TRUE) <= gesture_dis_min)
  		return FALSE;
  	gesture_buf[gesture_num ++].all = data_i;
  		return TRUE;
  }
  
  static void GestureInit(void)
  {
  	int i;
  	gesture_num_last = gesture_num;
  	gesture_num = 0;
  	gesture_deal = FALSE;
  	if(gesture_dis_min < 0 || gesture_dis_min > 64)
  		gesture_dis_min = 2;
  	for(i=0;i<5;i++)
  	{
  		multi_x[i].count = 0;
  		multi_o[i].count = 0;
  	}
  }
  
  static int GestureStretch(void)
  {
  	unsigned int x_max=0,x_min=0xffff,y_max=0,y_min=0xffff;
  	int i;
  // 	if(gesture_num <= GESTURE_SIZE_NUM/2)
  // 		return FALSE;
  	if(gesture_num >= GESTURE_BUF_SIZE)
  		return FALSE;
  	for(i=0;i<gesture_num;i++)
  	{
  		if(gesture_buf[i].x > x_max)
  			x_max = gesture_buf[i].x;
  		if(gesture_buf[i].x < x_min)
  			x_min = gesture_buf[i].x;
  		if(gesture_buf[i].y > y_max)
  			y_max = gesture_buf[i].y;
  		if(gesture_buf[i].y < y_min)
  			y_min = gesture_buf[i].y;
  	}
  	if(x_max < x_min+64*2 || y_max < y_min+64*3)
  		return FALSE;
  	for(i=0;i<gesture_num;i++)
  	{
  		gesture_buf[i].x = (gesture_buf[i].x - x_min) * GESTURE_SIZE_REFE / (x_max - x_min);
  		gesture_buf[i].y = (gesture_buf[i].y - y_min) * GESTURE_SIZE_REFE / (y_max - y_min);
  	}
  	return TRUE;
  }
  
  static int GestureLength(void)
  {
  	int i;
  	int len = 0;
  	for(i=1;i<gesture_num;i++)
  	{
  		len += GestureDistance(&gesture_buf[i],&gesture_buf[i-1],TRUE);
  	}
  	return len;
  }
  
  static void GestureStandard(void)
  {
  	int i,n,t;
  	int len_now = 0;
  	int len_his = 0;
  	int len_total = GestureLength();
  	gesture_standard[0].all = gesture_buf[0].all&0x0fffffff;
  	gesture_standard[GESTURE_SIZE_NUM - 1].all = gesture_buf[gesture_num -1].all&0x0fffffff;
  	for(i=1,n=0;i<GESTURE_SIZE_NUM-1;i++)
  	{
  		while(++n<gesture_num)
  		{
  			len_now = GestureDistance(&gesture_buf[n],&gesture_buf[n-1],TRUE);
  			len_his += len_now;
  			if(len_his*(GESTURE_SIZE_NUM-1) >= len_total*i)
  				break;
  		}
  		if(n >= gesture_num || len_now == 0)
  			break;
  		gesture_standard[i].all = 0;
  		t = (int)gesture_buf[n-1].x 
  			+ ((int)gesture_buf[n].x -  (int)gesture_buf[n-1].x)
  			* ((int)len_total*i/(GESTURE_SIZE_NUM-1) - (int)len_his + (int)len_now)
  			/ (int)len_now
  			;
  		if(t < 0)
  			t = 0;
  		gesture_standard[i].x = t;
  		t = (int)gesture_buf[n-1].y 
  			+ ((int)gesture_buf[n].y -  (int)gesture_buf[n-1].y)
  			* ((int)len_total*i/(GESTURE_SIZE_NUM-1) - (int)len_his + (int)len_now)
  			/ (int)len_now
  			;
  		if(t < 0)
  			t = 0;
  		gesture_standard[i].y = t;
  		n--;
  		len_his -= len_now;
  	}
  }
  
  static int GestureModel(const GESTURE_MODEL_TYPE * model,int len,int threshold,int *out)
  {
  	int offset[] = {-2,-1,0,1,2};
  	int ret_offset;
  	int i,j,k,n;
  	int min,min_n;
  	GESTURE_POINT_TYPE model_coor;
  	if(model == NULL || threshold <= 0 || len <= 0)
  	{
  		*out = 0x7fffffff;
  		return 0x7fffffff;
  	}
  	min=0x7fffffff;
  	min_n = 0;
  	for(j=0;j<len;j++)
  	{
  		for(k=0;k<sizeof(offset)/sizeof(offset[0]);k++)
  		{
  			n = 0;
  			ret_offset = 0;
  			for(i=0;i<GESTURE_SIZE_NUM;i++)
  			{
  				if(i+offset[k] < 0 || i+offset[k] >= GESTURE_SIZE_NUM)
  					continue;
  				if((i&1)==0)
  					model_coor.all = model[j].coor[i/2] & 0x00ff00ff;
  				else
  					model_coor.all = (model[j].coor[i/2]>>8) & 0x00ff00ff;
  				ret_offset += GestureDistance(&gesture_standard[i+offset[k]],&model_coor,FALSE);
  				n ++;
  			}
  			if(n == 0)
  				continue;
  			ret_offset = ret_offset / n * model[j].coe / 0x10;//coe <0x3fff
  			if(ret_offset < min)
  			{
  				min_n = j;
  				min = ret_offset;
  			}
  		}
  	}
  	if(min < threshold)
  		*out = model[min_n].out;
  	else
  		*out = 0x7fffffff;
  	return min;
  }
  
  static void ChangeXY(void)
  {
  	int i;
  	for(i=0;i<gesture_num && i<GESTURE_BUF_SIZE;i++)
  		gesture_buf[i].all = ((gesture_buf[i].all & 0xfff) << 16) + ((gesture_buf[i].all>>16) & 0xffff);
  }
  
  static void GestureSet(unsigned int conf[])
  {
  	if(conf == NULL)
  		return;
  	if(conf[0] >= 0 && conf[0] <= 64)
  		gesture_dis_min = conf[0];
  	else
  		gesture_dis_min = 0;
  	if(conf[1] != 0)
  		gesture_threshold[0] = conf[1];
  	else
  		gesture_threshold[0] = 0xfff;
  	gesture_threshold[1] = conf[2];
  	x_scale = (conf[3]==0) ? 4 : conf[3];
  	y_scale = (conf[4]==0) ? 4 : conf[4];
  	if(conf[5] == 0)
  	{
  		double_down = 2;
  		double_up = 30;
  	}
  	else
  	{
  		double_down = conf[5] & 0xffff;
  		double_up = conf[5] >> 16;
  	}
  	multi_set = conf[6];
  	gesture_flag = conf[7];
  }
  
  static void GestureOrientation(int ori)
  {
  	int i,t;
  	if(ori == 0)
  		return;
  	if(ori == 2)
  	{
  		for(i=0;i<GESTURE_SIZE_NUM;i++)
  		{
  			t = GESTURE_SIZE_REFE - gesture_standard[i].x;
  			gesture_standard[i].x = gesture_standard[i].y;
  			gesture_standard[i].y = t;
  		}
  	}
  	else if(ori == 1 || ori == 3)
  	{
  		for(i=0;i<GESTURE_SIZE_NUM;i++)
  		{
  			gesture_standard[i].x = GESTURE_SIZE_REFE - gesture_standard[i].x;
  			gesture_standard[i].y = GESTURE_SIZE_REFE - gesture_standard[i].y;
  		}
  	}
  	else if(ori == 4)
  	{
  		for(i=0;i<GESTURE_SIZE_NUM;i++)
  		{
  			t = GESTURE_SIZE_REFE - gesture_standard[i].y;
  			gesture_standard[i].y = gesture_standard[i].x;
  			gesture_standard[i].x = t;
  		}
  	}
  }
  
  static int GestureDeal(void)
  {
  	int i,j;
  	int gesture_out[2];
  	int gesture_val[2];
  	int gl[4];
  	int gv[4];
  
  	while(1)
  	{
  		if(gesture_last)
  			break;
  		gesture_last = gesture_multi;
  		if(gesture_last)
  			break;
  		gesture_last = double_click;
  		if(gesture_last)
  			break;
  		if(gesture_deal & GESTURE_XY)
  		{
  			gesture_deal &= ~GESTURE_XY;
  			ChangeXY();
  		}
  		if((gesture_deal & GESTURE_DEAL) == 0)
  			return FALSE;
  		gesture_deal &= ~GESTURE_DEAL;
  		gesture_last = GestureLRUD();
  		if(gesture_last)
  			break;
  		if(GestureStretch() == FALSE)
  			break;
  		GestureStandard();
  		for(j=0;j<4;j++)
  		{
  			gv[j] = 0x7fffffff;
  			GestureOrientation(j);
  			if(((gesture_flag & 0xf0) == 0 && j == 0)
  			|| ((gesture_flag & 0xf0) != 0 && (gesture_flag & (0x10<<j)) != 0))
  			{
  				gesture_val[0] =  GestureModel(model_default,sizeof(model_default)/sizeof(model_default[0]),gesture_threshold[0],&gesture_out[0]);
  				gesture_val[1] =  GestureModel(model_extern,model_extern_len,gesture_threshold[1],&gesture_out[1]);
  				for(i=0;i<2;i++)
  				{
  					if(gesture_val[i] <= gv[j])
  					{
  						gv[j] = gesture_val[i];
  						gl[j] = gesture_out[i];
  					}
  				}
  			}
  		}
  		gesture_value = 0x7fffffff;
  		for(j=0;j<4;j++)
  		{
  			if(gl[j] >= 'A' && gl[j] <= 'Z' && gv[j] < gesture_value)
  			{
  				gesture_value = gv[j];
  				gesture_last = gl[j];
  			}
  		}
  		if(gesture_value < 0x7fffffff)
  			break;
  		for(j=0;j<4;j++)
  		{
  			if(gv[j] < gesture_value)
  			{
  				gesture_value = gv[j];
  				gesture_last = gl[j];
  			}
  		}
  		break;
  	}
  	GestureInit();
  	i = gesture_last;
  	gesture_last = 0;
  	return i;
  }
  
  void gsl_GestureExtern(const GESTURE_MODEL_TYPE *model,int len)
  {
  	model_extern = model;
  	model_extern_len = len;
  }
  EXPORT_SYMBOL(gsl_GestureExtern);
  
  static int GestureLRUD(void)
  {
  	int x1=0,y1=0,x2=0,y2=0,i=0;
  	int flag3=0;
  	int middle_x;
  	int middle_y;
  	int min_scale=5;
  	if(gesture_deal & GESTURE_XY)
  	{
  		gesture_deal &= ~GESTURE_XY;
  		ChangeXY();
  	}
  	if((gesture_deal & GESTURE_LRUD) == 0)
  		return FALSE;
  	gesture_deal &= ~GESTURE_LRUD;
  //	int screen_x_max=0,screen_y_max=0;
  	x1=gesture_buf[0].x;//480
  	y1=gesture_buf[0].y;//800
  	x2=gesture_buf[gesture_num-1].x;
  	y2=gesture_buf[gesture_num-1].y;
  	middle_x =( x1 + x2)/2;
  	middle_y = (y1 + y2)/2;
  	for(i=1;i<gesture_num;i++)
  	{
  		if(abs(gesture_buf[i].x-middle_x)<(int)sen_num_nokey*64/x_scale)//screen_y_max/8)//30
  			flag3|=0x1;
  		else
  			flag3|=0x2;
  		if(abs(gesture_buf[i].y-middle_y)<(int)drv_num_nokey*64/y_scale)//screen_x_max/8)//25
  			flag3|=(0x1<<4);
  		else
  			flag3|=(0x2<<4);
  		if((int)gesture_buf[i].x-(int)gesture_buf[i-1].x>min_scale)
  			flag3|=(0x1<<8);
  		else if((int)gesture_buf[i].x-(int)gesture_buf[i-1].x<-min_scale)
  			flag3|=(0x2<<8);
  		if((int)gesture_buf[i].y-(int)gesture_buf[i-1].y>min_scale)
  			flag3|=(0x1<<12);
  		else if((int)gesture_buf[i].y-(int)gesture_buf[i-1].y<-min_scale)
  			flag3|=(0x2<<12);
  	}
  	if(1)
  	{
  		if((flag3==0x2031||flag3==0x2131||flag3==0x2231||flag3==0x2331))//&&(y2-y1>screen_x_max/3))
  			return 0xa1fc;//up(a1,fc)
  		else if((flag3==0x1031||flag3==0x1131||flag3==0x1231||flag3==0x1331))//&&(y1-y2>screen_x_max/3))
  			return 0xa1fd;//down
  		else if((flag3==0x213||flag3==0x1213||flag3==0x2213||flag3==0x2213))//&&(x2-x1>screen_y_max/3))
  			return 0xa1fb;//left
  		else if((flag3==0x113||flag3==0x1113||flag3==0x2113||flag3==0x3113))//&&(x1-x2>screen_y_max/3))
  			return 0xa1fa;//right
  	}
  	return FALSE;
  }
  
  static int GestureMulti(unsigned int *data_in)
  {
  #ifndef POINT_MAX
  #define	POINT_MAX		10
  #endif
  	GESTURE_POINT_TYPE *data = (GESTURE_POINT_TYPE*)data_in;
  	GESTURE_POINT_TYPE centre;
  	int n = 0;
  	int sum_x=0,sum_y=0,s = 0;
  	int i;
  	int msc,mse,msi;//multi_set_count,effective,invalid
  	if(multi_set == 0)
  	{
  		msc = 5;
  		mse = 8;
  		msi = 16;
  	}
  	else
  	{
  		msc = (multi_set >>  0) & 0xff;
  		mse = (multi_set >>  8) & 0xff;
  		msi = (multi_set >> 16) & 0xff;
  	}
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(data[i].all == 0 )
  			continue;
  		n++;
  		sum_x += data[i].x;
  		sum_y += data[i].y;
  	}
  	if(n == 0)
  	{
  		s = FALSE;
  		if(multi_x[5-1].count >= 0 && multi_x[4-1].count >= 0 && multi_x[5-1].count + multi_x[4-1].count >= msc)
  			s |= 0xbacf;
  		if(multi_o[5-1].count >= 0 && multi_o[4-1].count >= 0 && multi_o[5-1].count + multi_o[4-1].count >= msc)
  			s |= 0xb7d6;
  		if(s != 0xbacf && s != 0xb7d6)
  			s = FALSE;
  		for(i=0;i<5;i++)
  		{
  			multi_x[i].count = 0;
  			multi_o[i].count = 0;
  		}
  		return s;
  	}
  	if(n == 1 || n > 5)
  		return FALSE;
  	sum_x /= n;
  	sum_y /= n;
  	centre.all = 0;
  	centre.x = sum_x;
  	centre.y = sum_y;
  	s = 0;
  	for(i=0;i<POINT_MAX;i++)
  	{
  		if(data[i].all == 0 )
  			continue;
  		s += GestureDistance(&data[i],&centre,TRUE);
  	}
  	s /= n;
  	n--;
  	while(1)
  	{
  		if(multi_x[n].count == 0)
  		{
  			multi_x[n].count++;
  			multi_x[n].dis = s;
  			break;
  		}
  		if(multi_x[n].count < 0)
  			break;
  		if(s > multi_x[n].dis + msi)
  		{
  			multi_x[n].count = -1;
  			break;
  		}
  		if(s + mse < multi_x[n].dis)
  		{
  			multi_x[n].count++;
  			multi_x[n].dis = s;
  			break;
  		}	
  		break;
  	}
  	while(1)
  	{
  		if(multi_o[n].count == 0)
  		{
  			multi_o[n].count++;
  			multi_o[n].dis = s;
  			break;
  		}
  		if(multi_o[n].count < 0)
  			break;
  		if(s + msi < multi_o[n].dis)
  		{
  			multi_o[n].count = -1;
  			break;
  		}
  		if(s > multi_o[n].dis + mse)
  		{
  			multi_o[n].count++;
  			multi_o[n].dis = s;
  			break;
  		}	
  		break;
  	}
  	return FALSE;
  }
  
  unsigned int gsl_GestureBuffer(unsigned int **buf)
  {
  	int i;
  	if(gesture_num_last >= GESTURE_BUF_SIZE)
  		gesture_num_last = GESTURE_BUF_SIZE - 1;
  	for(i=0;i<gesture_num_last;i++)
  	{
  		gesture_buf[i].all = ScreenResolution((gsl_POINT_TYPE*)(&gesture_buf[i].all));
  	}
  	*buf = &(gesture_buf[0].all);
  	return gesture_num_last;
  }
  EXPORT_SYMBOL(gsl_GestureBuffer);
  
  
  
  #endif
  