2 * Microwindows touch screen driver for NEC Harrier Demo Board.
4 * Copyright (c) 2000 Century Software Embedded Technologies
6 * Requires /dev/tpanel kernel device driver for the VRC4173 chip
14 #include <sys/ioctl.h>
15 #include <linux/tpanel.h>
19 /* Very basic handling for the touch panel */
20 /* Mostly borrowed from mou_ipaq.c which I believe was mostly */
21 /* borrowed from mou_tp.c */
23 /* Define this if you want to use the filter instead of the average method */
24 /* #define USE_FILTER */
26 /* Defines used throughout */
27 #define TP_STATUS_HARDDATALOST 0x1000
28 #define TP_STATUS_SOFTDATALOST 0x2000
29 #define TP_STATUS_PENCONTACT 0x4000
30 #define TP_STATUS_DATAVALID 0x8000
32 /* Fix these when we know the right size */
34 #define TP_MIN_X_SIZE 291
35 #define TP_MIN_Y_SIZE 355
37 #define TP_MAX_X_SIZE 3839
38 #define TP_MAX_Y_SIZE 3711
49 #define MOU_SAMPLE_RATE 1
51 #define MOU_SAMPLE_RATE 10
54 #define MOU_READ_INTERVAL 5000
56 /* Data format (from kernel driver): */
57 /* unsigned short status */
58 /* unsigned short x+ (raw) */
59 /* unsigned short x- (raw) */
60 /* unsigned short y+ (raw) */
61 /* unsigned short y- (raw) */
62 /* unsigned short z (presssure, raw) */
64 static int pd_fd = -1;
65 int enable_pointing_coordinate_transform = 1;
67 static TRANSFORMATION_COEFFICIENTS tc;
70 extern SCREENDEVICE scrdev;
77 #define EPRINTF printf
78 #define DPRINTF printf
81 int GetPointerCalibrationData(void)
84 * Read the calibration data from the calibration file.
85 * Calibration file format is seven coefficients separated by spaces.
88 /* Get pointer calibration data from this file */
89 const char cal_filename[] = "/etc/pointercal";
93 FILE* f = fopen(cal_filename, "r");
96 EPRINTF("Error %d opening pointer calibration file %s.\n",
98 EPRINTF("Please type \"/usr/bin/tpcal > %s\" to calibrate\n",
103 items = fscanf(f, "%d %d %d %d %d %d %d",
104 &tc.a, &tc.b, &tc.c, &tc.d, &tc.e, &tc.f, &tc.s);
107 EPRINTF("Improperly formatted pointer calibration file %s.\n",
113 EPRINTF("a=%d b=%d c=%d d=%d e=%d f=%d s=%d\n",
114 tc.a, tc.b, tc.c, tc.d, tc.e, tc.f, tc.s);
120 inline MWPOINT DeviceToScreen(MWPOINT p)
123 * Transform device coordinates to screen coordinates.
124 * Take a point p in device coordinates and return the corresponding
125 * point in screen coodinates.
126 * This can scale, translate, rotate and/or skew, based on the
127 * coefficients calculated above based on the list of screen
128 * vs. device coordinates.
132 /* set slop at 3/4 pixel */
133 const short slop = TRANSFORMATION_UNITS_PER_PIXEL * 3 / 4;
137 new.x = (tc.a * p.x + tc.b * p.y + tc.c) / tc.s;
138 new.y = (tc.d * p.x + tc.e * p.y + tc.f) / tc.s;
140 /* hysteresis (thanks to John Siau) */
141 if ( abs(new.x - prev.x) >= slop )
142 out.x = (new.x | 0x3) ^ 0x3;
146 if ( abs(new.y - prev.y) >= slop )
147 out.y = (new.y | 0x3) ^ 0x3;
156 static int PD_Open(MOUSEDEVICE *pmd)
159 int settle_upper_limit;
162 /* Open the device */
163 pd_fd = open("/dev/tpanel", O_NONBLOCK);
167 EPRINTF("Error %d opening touch panel\n", errno);
171 s.interval = MOU_READ_INTERVAL;
174 * Upper limit on settle time is approximately (scan_interval / 5) - 60
175 * (5 conversions and some fixed overhead)
176 * The opmtimal value is the lowest that doesn't cause significant
180 settle_upper_limit = (s.interval / 5) - 60;
181 s.settletime = settle_upper_limit * 50 / 100;
182 result = ioctl(pd_fd, TPSETSCANPARM, &s);
185 EPRINTF("Error %d, result %d setting scan parameters.\n",
188 if (enable_pointing_coordinate_transform)
190 if (GetPointerCalibrationData() < 0)
197 /* We choose not to hide the cursor for now, others may want to */
201 /* Hide the cursor */
202 GdHideCursor(&scrdev);
209 static void PD_Close(void)
211 /* Close the touch panel device. */
217 static int PD_GetButtonInfo(void)
219 /* get "mouse" buttons supported */
223 static void PD_GetDefaultAccel(int *pscale,int *pthresh)
226 * Get default mouse acceleration settings
227 * This doesn't make sense for a touch panel.
228 * Just return something inconspicuous for now.
234 #define MAX_DEVICE_READS 10
235 static int read_tp(unsigned short *x, unsigned short *y,
236 unsigned short *z, int *b, unsigned short *status, unsigned char block)
238 unsigned char read_count = 0;
239 unsigned short tempx, tempy;
241 unsigned short data[6];
243 /* Uh, oh -- The driver is slow and fat, so we get lots of EAGAINS between */
244 /* reads. Thats never good. So we loop here for some count before we bail */
246 while(read_count < MAX_DEVICE_READS)
248 bytes_read = read(pd_fd, data, sizeof(data));
250 if (bytes_read != sizeof(data))
254 EPRINTF("Error reading touch panel. errno = %d\n", errno);
260 if (read_count++ == MAX_DEVICE_READS)
263 usleep(MOU_READ_INTERVAL / MAX_DEVICE_READS);
272 tempx = data[DATA_XPLUS];
273 tempy = data[DATA_YPLUS];
276 /* This is based on measured values. Occassionally, we get a bad read from the board */
277 /* This is to ensure that really wacked out reads don't get through. */
279 if ((data[DATA_STATUS] & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
281 if (enable_pointing_coordinate_transform)
283 if (tempx < TP_MIN_X_SIZE || tempx > TP_MAX_X_SIZE)
286 EPRINTF("Got an out of range X value. X=%d,Y=%d,B=%d\n",
288 ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
293 if (tempy < TP_MIN_Y_SIZE || tempy > TP_MAX_Y_SIZE)
296 EPRINTF("Got an out of range Y value. X=%d,Y=%d,B=%d\n",
298 ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0));
315 *b = ((data[DATA_STATUS] & TP_STATUS_PENCONTACT) ? MWBUTTON_L : 0);
316 *status = data[DATA_STATUS];
322 static int PD_Read(MWCOORD *px, MWCOORD *py, MWCOORD *pz, int *pb)
325 /* Filter stuff borrowed from mou_tp.c */
326 const int iir_shift_bits = 3;
327 const int iir_sample_depth = (1 << iir_shift_bits);
329 static int iir_accum_x = 0;
330 static int iir_accum_y = 0;
331 static int iir_accum_z = 0;
332 static int iir_count = 0;
337 /* Other local variables */
340 unsigned short samples = 0;
341 unsigned short xpos = 0;
342 unsigned short ypos = 0;
343 unsigned short zpos = 0;
344 unsigned short status = 0;
357 if ((err = read_tp(&xpos, &ypos, &zpos, pb, &status, 0)))
365 /* Check the status of the button */
367 if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
375 while((status & TP_STATUS_DATAVALID) == TP_STATUS_DATAVALID)
379 err = read_tp(&xpos, &ypos, &zpos, &tempb, &status, 1);
384 continue; /* We need at least one reading! */
386 break; /* The device continues to not respond. Bail */
391 /* If the data is invalid and the button is down, then bail */
392 /* Otherwise, record the button data */
394 if ( (status & TP_STATUS_DATAVALID) != TP_STATUS_DATAVALID)
397 return(0); /* Button is down, but data is invalid */
400 *pb = tempb; /* Record button up */
407 /* Run the newly aquired data through a filter */
408 /* is filter ready? */
409 if ( iir_count == iir_sample_depth )
411 /* make room for new sample */
412 iir_accum_x -= iir_accum_x >> iir_shift_bits;
413 iir_accum_y -= iir_accum_y >> iir_shift_bits;
414 iir_accum_z -= iir_accum_z >> iir_shift_bits;
416 /* feed new sample to filter */
437 /* Enough samples?? */
438 if (samples >= MOU_SAMPLE_RATE)
446 /* We're not done gathering samples yet */
447 if (iir_count < iir_sample_depth)
450 if (enable_pointing_coordinate_transform)
452 /* transform x,y to screen coords */
453 transformed.x = iir_accum_x;
454 transformed.y = iir_accum_y;
455 transformed = DeviceToScreen(transformed);
457 *px = transformed.x >> 2;
458 *py = transformed.y >> 2;
462 *px = (MWCOORD) abs(iir_accum_x);
463 *py = (MWCOORD) abs(iir_accum_y);
467 if (enable_pointing_coordinate_transform)
469 transformed.x = (cx / samples);
470 transformed.y = (cy / samples);
472 transformed = DeviceToScreen(transformed);
474 *px = (MWCOORD) transformed.x >> 2;
475 *py = (MWCOORD) transformed.y >> 2;
479 *px = (MWCOORD) abs(cx / samples);
480 *py = (MWCOORD) abs(cy / samples);
488 /* reset the filter */
497 return(2); /* XYZ and button data */
502 MOUSEDEVICE mousedev = {
513 int main(int argc, char ** v)
520 DPRINTF("Opening touch panel...\n");
522 if((result=PD_Open(0)) < 0)
525 DPRINTF("Error %d, result %d opening touch-panel\n", errno, result);
529 DPRINTF("Reading touch panel...\n");
533 result = PD_Read(&x, &y, &z, &b);
537 DPRINTF("(%d,%d,%d) b = %d\n",x, y, z, b);