2 * drivers/input/touchscreen/calibration_ts.c - calibration for rk2818 spi xpt2046 device and console
\r
4 * Copyright (C) 2010 ROCKCHIP, Inc.
\r
6 * This software is licensed under the terms of the GNU General Public
\r
7 * License version 2, as published by the Free Software Foundation, and
\r
8 * may be copied, distributed, and modified under those terms.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 #include <linux/kernel.h>
\r
16 #include <linux/string.h>
\r
18 #include "calibration_ts.h"
\r
19 #include "largenum_ts.h"
\r
21 #define MAX_POINT_ERROR 6
\r
24 PLARGENUM pa11, pa12, pa13;
\r
25 PLARGENUM pa21, pa22, pa23;
\r
26 PLARGENUM pa31, pa32, pa33;
\r
27 } MATRIX33, *PMATRIX33;
\r
38 CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER;
\r
40 static unsigned char v_Calibrated = 0;
\r
41 static CALIBRATION_PARAMETER v_CalcParam;
\r
45 int cCalibrationPoints, //@PARM The number of calibration points
\r
46 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
47 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
48 int *pUncalXBuffer, //@PARM List of X coords collected
\r
49 int *pUncalYBuffer //@PARM List of Y coords collected
\r
59 TouchPanelSetCalibration(
\r
60 int cCalibrationPoints, //@PARM The number of calibration points
\r
61 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
62 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
63 int *pUncalXBuffer, //@PARM List of X coords collected
\r
64 int *pUncalYBuffer //@PARM List of Y coords collected
\r
69 LARGENUM a31, a32, a33;
\r
70 LARGENUM b11, b12, b13;
\r
71 LARGENUM b21, b22, b23;
\r
78 LARGENUM a1, b1, c1;
\r
79 LARGENUM a2, b2, c2;
\r
86 //DEBUGMSG(1,(__TEXT("calibrating %d point set\r\n"), cCalibrationPoints));
\r
89 // If the calibration data is being cleared, set the flag so
\r
90 // that the conversion operation is a noop.
\r
93 if ( cCalibrationPoints == 0 )
\r
100 // Compute these large numbers
\r
102 LargeNumSet(&a11, 0);
\r
103 LargeNumSet(&a21, 0);
\r
104 LargeNumSet(&a31, 0);
\r
105 LargeNumSet(&a22, 0);
\r
106 LargeNumSet(&a32, 0);
\r
107 LargeNumSet(&a33, cCalibrationPoints);
\r
108 LargeNumSet(&b11, 0);
\r
109 LargeNumSet(&b12, 0);
\r
110 LargeNumSet(&b13, 0);
\r
111 LargeNumSet(&b21, 0);
\r
112 LargeNumSet(&b22, 0);
\r
113 LargeNumSet(&b23, 0);
\r
114 for(i=0; i<cCalibrationPoints; i++){
\r
115 LargeNumSet(&lnTouchX, pUncalXBuffer[i]);
\r
116 LargeNumSet(&lnTouchY, pUncalYBuffer[i]);
\r
117 LargeNumSet(&lnScreenX, pScreenXBuffer[i]);
\r
118 LargeNumSet(&lnScreenY, pScreenYBuffer[i]);
\r
119 LargeNumMult(&lnTouchX, &lnTouchX, &lnTemp);
\r
120 LargeNumAdd(&a11, &lnTemp, &a11);
\r
121 LargeNumMult(&lnTouchX, &lnTouchY, &lnTemp);
\r
122 LargeNumAdd(&a21, &lnTemp, &a21);
\r
123 LargeNumAdd(&a31, &lnTouchX, &a31);
\r
124 LargeNumMult(&lnTouchY, &lnTouchY, &lnTemp);
\r
125 LargeNumAdd(&a22, &lnTemp, &a22);
\r
126 LargeNumAdd(&a32, &lnTouchY, &a32);
\r
127 LargeNumMult(&lnTouchX, &lnScreenX, &lnTemp);
\r
128 LargeNumAdd(&b11, &lnTemp, &b11);
\r
129 LargeNumMult(&lnTouchY, &lnScreenX, &lnTemp);
\r
130 LargeNumAdd(&b12, &lnTemp, &b12);
\r
131 LargeNumAdd(&b13, &lnScreenX, &b13);
\r
132 LargeNumMult(&lnTouchX, &lnScreenY, &lnTemp);
\r
133 LargeNumAdd(&b21, &lnTemp, &b21);
\r
134 LargeNumMult(&lnTouchY, &lnScreenY, &lnTemp);
\r
135 LargeNumAdd(&b22, &lnTemp, &b22);
\r
136 LargeNumAdd(&b23, &lnScreenY, &b23);
\r
139 Matrix.pa11 = &a11;
\r
140 Matrix.pa21 = &a21;
\r
141 Matrix.pa31 = &a31;
\r
142 Matrix.pa12 = &a21;
\r
143 Matrix.pa22 = &a22;
\r
144 Matrix.pa32 = &a32;
\r
145 Matrix.pa13 = &a31;
\r
146 Matrix.pa23 = &a32;
\r
147 Matrix.pa33 = &a33;
\r
148 ComputeMatrix33(&delta, &Matrix);
\r
150 Matrix.pa11 = &b11;
\r
151 Matrix.pa21 = &b12;
\r
152 Matrix.pa31 = &b13;
\r
153 ComputeMatrix33(&a1, &Matrix);
\r
155 Matrix.pa11 = &a11;
\r
156 Matrix.pa21 = &a21;
\r
157 Matrix.pa31 = &a31;
\r
158 Matrix.pa12 = &b11;
\r
159 Matrix.pa22 = &b12;
\r
160 Matrix.pa32 = &b13;
\r
161 ComputeMatrix33(&b1, &Matrix);
\r
163 Matrix.pa12 = &a21;
\r
164 Matrix.pa22 = &a22;
\r
165 Matrix.pa32 = &a32;
\r
166 Matrix.pa13 = &b11;
\r
167 Matrix.pa23 = &b12;
\r
168 Matrix.pa33 = &b13;
\r
169 ComputeMatrix33(&c1, &Matrix);
\r
171 Matrix.pa13 = &a31;
\r
172 Matrix.pa23 = &a32;
\r
173 Matrix.pa33 = &a33;
\r
174 Matrix.pa11 = &b21;
\r
175 Matrix.pa21 = &b22;
\r
176 Matrix.pa31 = &b23;
\r
177 ComputeMatrix33(&a2, &Matrix);
\r
179 Matrix.pa11 = &a11;
\r
180 Matrix.pa21 = &a21;
\r
181 Matrix.pa31 = &a31;
\r
182 Matrix.pa12 = &b21;
\r
183 Matrix.pa22 = &b22;
\r
184 Matrix.pa32 = &b23;
\r
185 ComputeMatrix33(&b2, &Matrix);
\r
187 Matrix.pa12 = &a21;
\r
188 Matrix.pa22 = &a22;
\r
189 Matrix.pa32 = &a32;
\r
190 Matrix.pa13 = &b21;
\r
191 Matrix.pa23 = &b22;
\r
192 Matrix.pa33 = &b23;
\r
193 ComputeMatrix33(&c2, &Matrix);
\r
197 LARGENUM halfDelta;
\r
199 // Take care of possible truncation error in later mapping operations
\r
201 if(IsLargeNumNegative(&delta)){
\r
202 LargeNumDivInt32(&delta, -2, &halfDelta);
\r
204 LargeNumDivInt32(&delta, 2, &halfDelta);
\r
206 LargeNumAdd(&c1, &halfDelta, &c1);
\r
207 LargeNumAdd(&c2, &halfDelta, &c2);
\r
212 // All the numbers are determined now.
\r
213 // Let's scale them back to 32 bit world
\r
216 cShift = LargeNumBits(&a1) - MAX_COEFF_PRECISION;
\r
217 if(cShift > minShift){
\r
220 cShift = LargeNumBits(&b1) - MAX_COEFF_PRECISION;
\r
221 if(cShift > minShift){
\r
224 cShift = LargeNumBits(&a2) - MAX_COEFF_PRECISION;
\r
225 if(cShift > minShift){
\r
228 cShift = LargeNumBits(&b2) - MAX_COEFF_PRECISION;
\r
229 if(cShift > minShift){
\r
232 cShift = LargeNumBits(&c1) - MAX_TERM_PRECISION;
\r
233 if(cShift > minShift){
\r
236 cShift = LargeNumBits(&c2) - MAX_TERM_PRECISION;
\r
237 if(cShift > minShift){
\r
240 cShift = LargeNumBits(&delta) - 31;
\r
241 if(cShift > minShift){
\r
246 // Now, shift count is determined, shift all the numbers
\r
247 // right to obtain the 32-bit signed values
\r
250 LargeNumRAShift(&a1, minShift);
\r
251 LargeNumRAShift(&a2, minShift);
\r
252 LargeNumRAShift(&b1, minShift);
\r
253 LargeNumRAShift(&b2, minShift);
\r
254 LargeNumRAShift(&c1, minShift);
\r
255 LargeNumRAShift(&c2, minShift);
\r
256 LargeNumRAShift(&delta, minShift);
\r
258 v_CalcParam.a1 = a1.u.s32.u[0];
\r
259 v_CalcParam.b1 = b1.u.s32.u[0];
\r
260 v_CalcParam.c1 = c1.u.s32.u[0];
\r
261 v_CalcParam.a2 = a2.u.s32.u[0];
\r
262 v_CalcParam.b2 = b2.u.s32.u[0];
\r
263 v_CalcParam.c2 = c2.u.s32.u[0];
\r
264 v_CalcParam.delta = delta.u.s32.u[0];
\r
266 // Don't allow delta to be zero, since it gets used as a divisor
\r
267 if( ! v_CalcParam.delta )
\r
269 //RETAILMSG(1,(__TEXT("TouchPanelSetCalibration: delta of 0 invalid\r\n")));
\r
270 //RETAILMSG(1,(__TEXT("\tCalibration failed.\r\n")));
\r
271 v_CalcParam.delta = 1; // any non-zero value to prevents DivByZero traps later
\r
277 return ErrorAnalysis(
\r
278 cCalibrationPoints,
\r
294 LargeNumMult(pMatrix->pa11, pMatrix->pa22, &lnTemp);
\r
295 LargeNumMult(pMatrix->pa33, &lnTemp, pResult);
\r
296 LargeNumMult(pMatrix->pa21, pMatrix->pa32, &lnTemp);
\r
297 LargeNumMult(pMatrix->pa13, &lnTemp, &lnTemp);
\r
298 LargeNumAdd(pResult, &lnTemp, pResult);
\r
299 LargeNumMult(pMatrix->pa12, pMatrix->pa23, &lnTemp);
\r
300 LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);
\r
301 LargeNumAdd(pResult, &lnTemp, pResult);
\r
302 LargeNumMult(pMatrix->pa13, pMatrix->pa22, &lnTemp);
\r
303 LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);
\r
304 LargeNumSub(pResult, &lnTemp, pResult);
\r
305 LargeNumMult(pMatrix->pa12, pMatrix->pa21, &lnTemp);
\r
306 LargeNumMult(pMatrix->pa33, &lnTemp, &lnTemp);
\r
307 LargeNumSub(pResult, &lnTemp, pResult);
\r
308 LargeNumMult(pMatrix->pa23, pMatrix->pa32, &lnTemp);
\r
309 LargeNumMult(pMatrix->pa11, &lnTemp, &lnTemp);
\r
310 LargeNumSub(pResult, &lnTemp, pResult);
\r
314 TouchPanelCalibrateAPoint(
\r
315 int UncalX, //@PARM The uncalibrated X coordinate
\r
316 int UncalY, //@PARM The uncalibrated Y coordinate
\r
317 int *pCalX, //@PARM The calibrated X coordinate
\r
318 int *pCalY //@PARM The calibrated Y coordinate
\r
323 if ( !v_Calibrated )
\r
325 *pCalX = 200; //UncalX;
\r
326 *pCalY = 160; //UncalY;
\r
330 // Note the *4 in the expression below. This is a workaround
\r
331 // on behalf of gwe. It provides a form of
\r
332 // sub-pixel accuracy desirable for inking
\r
334 x = (v_CalcParam.a1 * UncalX + v_CalcParam.b1 * UncalY +
\r
335 v_CalcParam.c1) * 4 / v_CalcParam.delta;
\r
336 y = (v_CalcParam.a2 * UncalX + v_CalcParam.b2 * UncalY +
\r
337 v_CalcParam.c2) * 4 / v_CalcParam.delta;
\r
352 int cCalibrationPoints, //@PARM The number of calibration points
\r
353 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
354 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
355 int *pUncalXBuffer, //@PARM List of X coords collected
\r
356 int *pUncalYBuffer //@PARM List of Y coords collected
\r
360 unsigned int maxErr, err;
\r
363 unsigned int errThreshold = MAX_POINT_ERROR; // Can be overridden by registry entry
\r
365 unsigned int status, ValType, ValLen;
\r
370 // See if there is a Maximum Calibration Error specified in the registry
\r
371 //status = RegOpenKeyEx(
\r
372 // HKEY_LOCAL_MACHINE,
\r
373 // __TEXT("HARDWARE\\DEVICEMAP\\TOUCH"),
\r
377 if ( status == ERROR_SUCCESS ) {
\r
378 ValLen = sizeof(errThreshold);
\r
379 status = RegQueryValueEx(
\r
381 __TEXT("MaxCalError"),
\r
384 (PUCHAR)&errThreshold,
\r
386 // We don't care what happened. Either we have a new value or we have the default value.
\r
387 RegCloseKey(regKey);
\r
390 RETAILMSG(1,(__TEXT("Maximum Allowed Error %d:\r\n"),
\r
392 DEBUGMSG(1,(__TEXT("Calibration Results:\r\n")));
\r
396 //DEBUGMSG(1,(__TEXT(" Screen => Mapped\r\n")));
\r
397 for(i=0; i<cCalibrationPoints; i++){
\r
398 TouchPanelCalibrateAPoint( pUncalXBuffer[i],
\r
405 printk("(%4d, %4d) => (%4d, %4d)\n",
\r
406 //DEBUGMSG(1,(__TEXT("(%4d, %4d) => (%4d, %4d)\r\n"),
\r
412 dx = x - pScreenXBuffer[i];
\r
413 dy = y - pScreenYBuffer[i];
\r
414 err = dx * dx + dy * dy;
\r
419 //DEBUGMSG(1,(__TEXT("Maximum error (square of Euclidean distance in screen units) = %u\r\n"),
\r
423 if (maxErr < (errThreshold * errThreshold))
\r
429 memset(&v_CalcParam, 0, sizeof(v_CalcParam));
\r
441 int screen_x[4], screen_y[4];
\r
442 int uncali_x[4], uncali_y[4];
\r
443 int tst_uncali_x, tst_uncali_y, tst_cali_x, tst_cali_y;
\r
445 screen_x[0] = 15; screen_y[0] = 15;
\r
446 screen_x[1] = 15; screen_y[1] = 465;
\r
447 screen_x[2] = 785; screen_y[2] = 15;
\r
448 screen_x[3] = 785; screen_y[3] = 465;
\r
450 uncali_x[0] = 173; uncali_y[0] = 417;
\r
451 uncali_x[1] = 148; uncali_y[1] = 3867;
\r
452 uncali_x[2] = 3903; uncali_y[2] = 365;
\r
453 uncali_x[3] = 3924; uncali_y[3] = 3863;
\r
455 ret = TouchPanelSetCalibration(4, screen_x,
\r
456 screen_y, uncali_x, uncali_y);
\r
458 printf("TouchPanelSetCalibration OK.\n");
\r
460 printf("TouchPanelSetCalibration FAIL.\n");
\r
462 tst_uncali_x = 2033;
\r
463 tst_uncali_y = 2132;
\r
465 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
466 &tst_cali_x, &tst_cali_y);
\r
468 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
469 tst_cali_x/4, tst_cali_y/4);
\r
471 tst_uncali_x = 170;
\r
472 tst_uncali_y = 418;
\r
474 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
475 &tst_cali_x, &tst_cali_y);
\r
477 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
478 tst_cali_x/4, tst_cali_y/4);
\r
480 tst_uncali_x = 500;
\r
481 tst_uncali_y = 707;
\r
483 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
484 &tst_cali_x, &tst_cali_y);
\r
486 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
487 tst_cali_x/4, tst_cali_y/4);
\r
489 tst_uncali_x = 3636;
\r
490 tst_uncali_y = 2150;
\r
492 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
493 &tst_cali_x, &tst_cali_y);
\r
495 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
496 tst_cali_x/4, tst_cali_y/4);
\r