📄 s3c2410-ts.c
字号:
/* * linux/drivers/char/s3c2410_ts.c * * Copyright (C) 2002 SAMSUNG ELECTRONICS SW.LEE <hitchcar@sec.samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ /* * Using the hareware timer1 instead of software timer (struct timer_list) * raw device not implemented * calibration not implemented */#include <linux/module.h>#include <linux/types.h>#include <linux/wait.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/init.h>#include <linux/compiler.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/hardware.h>#include "s3c2410-ts.h"#include <asm/arch/S3C2410.h>#include <asm/arch/cpu_s3c2410.h>/* * TSBUF_SIZE must be a power of two */#define S3C2410_TS_MINOR 0#define H3600_TS_MODULE_NAME "ts"#define INCBUF(x,mod) (((x)+1) & ((mod) - 1))#define MOUSEBUF_SIZE 32#define DOWN_PRESS 1#define UP_PRESS 0#define NO_PRESS 0#define TS_FILTER_LENGTH 8#define XLIMIT 0x8 #define YLIMIT 0x10#define TOUCH_ORG_OFFSET_X 0x110//75#define TOUCH_ORG_OFFSET_Y 0xe8//40#define TOUCH_ADC_MAX_X 0x3b6//880/* org 1000 */#define TOUCH_ADC_MAX_Y 0x3b7//890/* org 980 */#define TOUCH_STOP_BUT_QUIVER 3/* * I used "h3600_ts" name to use the ramdisk image containing x demo * from www.handhelds.org * */static char *g_ts_id = "h3600_ts ChangeMe"; /* global touch screen id for irq*/static char *g_ts_timer_id = "touchscreen timer"; /* global touch screen timer id for irq */#define ADC_FREQ 2000000 // 2MHz AD convert freq 030918static int PreScale_n; // PCLK / (PreScale_n+1) = ADConversion freq.struct s3c2410_ts_general { unsigned int head, tail; /* Position in the event buffer */ struct fasync_struct *async_queue; /* Asynchronous notification */ wait_queue_head_t waitq; /* Wait queue for reading */ struct semaphore lock; /* Mutex for reading */ unsigned int usage_count; /* Increment on each open */ unsigned int total; /* Total events */ unsigned int processed; unsigned int dropped; };typedef struct config_data{ int x0,y0,x1,y1,x2,y2,x3,y3; // touch screen verify}config_data;struct config_data cfg_data = {0x110, 0xe8, 0, 0, 0, 0, 0x3b6, 0x3b7};struct s3c2410_ts_device { struct s3c2410_ts_general d; struct s3c2410_ts_calibration cal; /* ts calibration parameters */ struct s3c2410_ts_event buf[MOUSEBUF_SIZE]; struct s3c2410_ts_event cur_data, samples[3],last_data;};/* I think.. * if multiple open happens, global_tc ==> global_ts[open_count] */struct s3c2410_ts_device global_ts;enum pen_state { PEN_UP = 0, PEN_DOWN , PEN_SAMPLE};enum ts_timer { TTIMER_SETUP, TTIMER_START, TTIMER_STOP};int global_ts_justified = 1;int global_ts_justify_status = 0;int global_ts_status = PEN_UP;struct ts_pen_data { enum pen_state state; unsigned short x[TS_FILTER_LENGTH]; // Unfiltered data points unsigned short y[TS_FILTER_LENGTH]; unsigned short count; // Number of points recorded in this "DOWN" or "DISCARD" series unsigned short index; // Location in ring buffer of last stored data value int last_cal_x; // Last reported X value to the user int last_cal_y; // Last reported Y value to the user};struct ts_pen_data pen_data;static void s3c2410_ts_handler(void);static int ts_timer_operation(enum ts_timer tt);static int data_processing(void){ struct s3c2410_ts_device * dev = &global_ts; int diff0, diff1, diff2; int RetVal = 0; /* default valid */ struct s3c2410_ts_event *samples =dev->samples ; dev->cur_data.x = samples[0].x; dev->cur_data.y = samples[0].y; /* * Check the variance between X samples (discard if not similar), * then choose the closest pair */ diff0 = abs(samples[0].x - samples[1].x); diff1 = abs(samples[1].x - samples[2].x); diff2 = abs(samples[2].x - samples[0].x);// if (diff0 > XLIMIT || diff1 > XLIMIT || diff2 > XLIMIT )// return XLIMIT ; /* invalid */ if (diff1 < diff2) { if (diff1 < diff0) dev->cur_data.x = (samples[1].x + samples[2].x) / 2; else dev->cur_data.x = (samples[0].x + samples[1].x) / 2; } else { if (diff2 < diff0) dev->cur_data.x = (samples[2].x + samples[0].x) / 2; else dev->cur_data.x = (samples[0].x + samples[1].x) / 2; }/* Do the same for Y */ diff0 = abs(samples[0].y - samples[1].y); diff1 = abs(samples[1].y - samples[2].y); diff2 = abs(samples[2].y - samples[0].y); // if (diff0 > YLIMIT || diff1 > YLIMIT || diff2 > YLIMIT )// return YLIMIT; if (diff1 < diff2) { if (diff1 < diff0) dev->cur_data.y = (samples[1].y + samples[2].y) / 2; else dev->cur_data.y = (samples[0].y + samples[0].y) / 2; } else { if (diff2 < diff0) dev->cur_data.y = (samples[2].y + samples[0].y) / 2; else dev->cur_data.y = (samples[0].y + samples[1].y) / 2; } if(global_ts_justified == 0) { if(global_ts_status == PEN_DOWN){ } else if(global_ts_status == PEN_UP){ return; }else{ global_ts_status = pen_data.state; return; } if(global_ts_status == PEN_SAMPLE) return; if(global_ts_justify_status == 0) { printk("the left top point (0x%x, 0x%x)\n", dev->cur_data.x, dev->cur_data.y); cfg_data.x0 = dev->cur_data.x; cfg_data.y0 = dev->cur_data.y; global_ts_justify_status = 1; global_ts_status = PEN_SAMPLE; }else if(global_ts_justify_status == 1) { printk("the right bottom point (0x%x, 0x%x)\n", dev->cur_data.x, dev->cur_data.y); cfg_data.x3 = dev->cur_data.x; cfg_data.y3 = dev->cur_data.y; global_ts_justify_status = 0; global_ts_justified = 1; global_ts_status = PEN_SAMPLE; } }#if 0 printk("cur_data.x = 0x%x, cur_data.y = 0x%x\n", dev->cur_data.x, dev->cur_data.y);#endif return RetVal; dev->cur_data.x -= cfg_data.x0; if ( dev->cur_data.x > 40000) dev->cur_data.x = 0; dev->cur_data.y -= cfg_data.y3; if ( dev->cur_data.y > 40000) dev->cur_data.y = 0; dev->cur_data.x = (dev->cur_data.x*CURRENT_LCD_X)/(cfg_data.x3 - cfg_data.x0); dev->cur_data.y = CURRENT_LCD_Y - (dev->cur_data.y*CURRENT_LCD_Y)/(cfg_data.y0 - cfg_data.y3); if(dev->cur_data.x > CURRENT_LCD_X ) dev->cur_data.x = CURRENT_LCD_X; if(dev->cur_data.y > CURRENT_LCD_Y ) dev->cur_data.y = CURRENT_LCD_Y;#if 0 printk("dev->cur_data.x = %d, dev->cur_data.y = %d\n", dev->cur_data.x, dev->cur_data.y);#endif if ( (abs(dev->last_data.x - dev->cur_data.x) <= TOUCH_STOP_BUT_QUIVER) && (abs(dev->last_data.y - dev->cur_data.y) <= TOUCH_STOP_BUT_QUIVER) ) { dev->cur_data = dev->last_data; } else { dev->last_data = dev->cur_data; } return RetVal;}static void touch_timer_irq(int irq, void *dev_id, struct pt_regs *regs){ if( (ADCDAT0&0x8000)||(ADCDAT1&0x8000)) { ts_timer_operation(TTIMER_STOP); pen_data.state = PEN_UP; s3c2410_ts_handler(); return; } switch(pen_data.state) { case PEN_UP: ts_timer_operation(TTIMER_STOP); s3c2410_ts_handler(); return; case PEN_DOWN: pen_data.state = PEN_SAMPLE; s3c2410_ts_handler(); return; case PEN_SAMPLE: if( (ADCDAT0&0x8000)||(ADCDAT1&0x8000)) { ts_timer_operation(TTIMER_STOP); pen_data.state = PEN_UP; s3c2410_ts_handler(); return; } else { pen_data.state = PEN_SAMPLE; s3c2410_ts_handler(); return; } default: printk(__FUNCTION__ " UNEXPECTED ERROR %d \n",pen_data.state); }}/* * Interrupt handler and standard file operations */static void ts_down_interrupt(int irq, void *dev_id, struct pt_regs *regs){ if ( (ADCDAT1&0x8000)|| (ADCDAT0&0x8000) ) { pen_data.state = PEN_UP; } else { pen_data.state = PEN_DOWN; } s3c2410_ts_handler();}static void ts_up_interrupt(int irq, void *dev_id, struct pt_regs *regs){ if ( (ADCDAT1&0x8000)|| (ADCDAT0&0x8000) ) { pen_data.state = PEN_UP; } else { pen_data.state = PEN_DOWN; } s3c2410_ts_handler();}static void s3c2410_ts_handler(){ int index_ret; struct s3c2410_ts_device * dev = &global_ts; unsigned int nhead = INCBUF( dev->d.head, MOUSEBUF_SIZE ); struct s3c2410_ts_event *event = &dev->buf[dev->d.head]; switch (pen_data.state) { case PEN_UP: global_ts_status = PEN_UP; ts_timer_operation(TTIMER_STOP); ADCTSC &= 0xff; //pen_data.state = PEN_DOWN; break; case PEN_DOWN: if(global_ts_status == PEN_UP) global_ts_status = PEN_DOWN; ts_timer_operation(TTIMER_START);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -