您的位置:首页 > 编程语言

S3C2410触摸屏驱动代码分析2

2008-08-03 16:37 435 查看
#define mode_x_axis_n() { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | /
XP_PULL_UP_DIS | XP_PST(NOP_MODE); }
/*基本配置和上面相同,就是不进行x 坐标的转换*/
#define mode_y_axis() { ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT | YM_GND | /
XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE); }
/*对Y 坐标开始进行测量
*/

#define start_adc_x() { ADCCON = PRESCALE_EN | PRSCVL(49) | /
ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | /
ADC_NORMAL_MODE; /
ADCDAT0; }
/*首先设置ADCCON 寄存器,开始转换x 坐标,因为在ADCCON 寄存器中,已经设置通
过读取数据寄存器来启动转换,所以在执行ADCDAT0 宏时(该宏从ADCDATA0 寄存器中
读取数据),A/D 转换器即开始转换数据。
宏ADCDAT0 定义为:
#define ADCDAT0 bADC_CTL(oADCDAT0)
。。。。。
#define bADC_CTL(Nb) __REG(ADC_CTL_BASE + (Nb))
*/

#define start_adc_y() { ADCCON = PRESCALE_EN | PRSCVL(49) | /
ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | /
ADC_NORMAL_MODE; /
ADCDAT1; }
/*
首先设置ADCCON 寄存器,开始转换y 坐标,因为在ADCCON 寄存器中,已经设置
通过读取数据寄存器来启动转换,所以在执行ADCDAT1 宏时(该宏从ADCDATA1 寄存器
中读取数据),A/D 转换器即开始转换数据。
宏ADCDAT1 定义为:
#define ADCDAT1 bADC_CTL(oADCDAT1)
。。。。。

#define bADC_CTL(Nb) __REG(ADC_CTL_BASE + (Nb))
49
*/
#define disable_ts_adc() { ADCCON &= ~(ADCCON_READ_START); }
/*
停止转换
*/
static unsigned int adc_state = 0;
static unsigned int x, y; /* touch screen coorinates */
static unsigned int time=0;
#define CHEAT_NUMBER 40
static unsigned int cheat = 0;
static unsigned int cheat_y[CHEAT_NUMBER] = {0,};
static unsigned int cheat_diff_y = 0;
static unsigned int cheat_x[CHEAT_NUMBER] = {0,};
static unsigned int cheat_diff_x = 0;
49
static void tsEvent_raw(void)
{
if (tsdev.penStatus == PEN_DOWN)
{
#ifdef UP_TS
BUF_HEAD.x = x;
BUF_HEAD.y = y;
#endif
#ifdef DOWN_TS
BUF_HEAD.x = y;//x;
BUF_HEAD.y = x;//y;
#endif
BUF_HEAD.pressure = PEN_DOWN;
/*
将结果存放到环形缓冲区的head 指针所指向的位置。
*/
#ifdef HOOK_FOR_DRAG
ts_timer.expires = jiffies + TS_TIMER_DELAY;
add_timer(&ts_timer);
#endif
}
else
{
#ifdef HOOK_FOR_DRAG
del_timer(&ts_timer);
#endif
BUF_HEAD.x = 0;
BUF_HEAD.y = 0;
BUF_HEAD.pressure = PEN_UP;
}
tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);
/*
在触摸屏设备的环形队列中,将head 指针向下移动一位
*/
wake_up_interruptible(&(tsdev.wq));
/*
如果有相关的设备被阻塞在这个队列的时候,就去唤醒它。
比如,在应用程序中,我们首先打开触摸屏设备,然后用read 函数去读其中的内容,
但是由于还没有点击触摸屏,所以应用进程就会被阻塞,等到用户点击触摸屏后,会调用
wake_up_interruptible()通知被阻塞的用户解除阻塞。
*/
#ifdef USE_ASYNC
if (tsdev.aq)
kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);
#endif
#ifdef CONFIG_PM
pm_access(tsdev.pm_dev);
#endif
}
static int tsRead(TS_RET * ts_ret)
{
spin_lock_irq(&(tsdev.lock));
ts_ret->x = BUF_TAIL.x;
ts_ret->y = BUF_TAIL.y;
ts_ret->pressure = BUF_TAIL.pressure;
tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);
spin_unlock_irq(&(tsdev.lock));
/*
从环形缓冲区的尾部取数据
*/
return sizeof(TS_RET);
}
static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
TS_RET ts_ret;
retry:
if (tsdev.head != tsdev.tail) {
int count;
count = tsRead(&ts_ret);
if (count) copy_to_user(buffer, (char *)&ts_ret, count);
return count;
} else {
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&(tsdev.wq));
if (signal_pending(current))
return -ERESTARTSYS;
goto retry;
}
/*
首先调用tsdev.head != tsdev.tail 判断环形缓冲区中是否有数据,如果有则执行tsRead()
函数从环形缓冲区中读出其里面的一项值,并把结果通过copy_to_user()返回到用户空间中。
如果环形缓冲区中没有数据,则首先判断用户程序中的打开该设备文件时是否使用阻塞
方式(默认为阻塞方式),还是非阻塞方式(如打开时使用fd=open(“/dev/s3c2410-ts”,
O_RDONLY|O_NONBLOCK))。如果采用非阻塞方式,返回EAGAIN 错误码。采用阻塞方
式时,则会调用interruptible_sleep_on()函数通知应用进程进入睡眠状态,而内核中
s3c2410_ts_read()函数会不停的测试相应的位,直到环形缓冲区中有数据为止。
*/
return sizeof(TS_RET);
}
#ifdef USE_ASYNC
static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)
{
return fasync_helper(fd, filp, mode, &(tsdev.aq));
}
#endif
static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)
{
poll_wait(filp, &(tsdev.wq), wait);
return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);
}
static inline void start_ts_adc(void)
{
adc_state = 0;
/*
标识一次触摸屏转换的开始
*/
mode_x_axis();
start_adc_x();
/*
首先调用mode_x_axis()函数来完成x 坐标转换的前期准备工作,然后调用start_adc_x()
来完成x 坐标正在转换的开始。
在start_adc_x()函数中会触发一次触摸屏中断,这是由于在该函数中设置了启动触摸屏
AD 转换的方式是读取AD 数据寄存器的值,而且在该函数的最后读取AD 数据寄存器0 的
值,所以引发一次AD 转换中断。
*/
time = 0;
/*
主要用于时间测量,在很多触摸屏驱动中,都会定义一个定时器,该定时器能够处理触
摸笔抖动问题
*/
}
static inline void s3c2410_get_XY(void)
{
const int TIMES = 60;
unsigned int i, tmp,j;
static unsigned int max, min;
static unsigned int data[60];
if (adc_state == 0)
{
if (time == 0)
{
y = 0;
//max = 0;
//min = 0xffffffff;
}
if (time < TIMES)
{
disable_ts_adc();
data[time] = (ADCDAT0 & 0x3ff);
//if (tmp > max) max = tmp;
//if (tmp < min) min = tmp;
//y += tmp;
start_adc_x();
time++;
/*
红颜色标注的代码被执行60 次,因为第一次被执行的时候time 值为0,adc_state 为0,
其中会执行start_adc_x()函数一次,即发生AD 中断一次,time 变量变为1。第二次中断再
次执行这段代码,重复刚才的步骤,一直等到执行60 次,即time 变量值等于60 时,才会
去执行下面蓝颜色标识的代码。每次中断时都会重新执行一次有关X 坐标的转换,所以
X 坐标被转换了60 次,每次转换的值存放在data 数组中。
*/
}
else
{
for (i = 0; i < TIMES; i++)
{
for (j = 0; j < TIMES - i; j++)
{
if (data[j] > data[j+1])
{
tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
}
}
}
/*
将刚才转换的60 次x 坐标进行排序,采用冒泡排序,排序后data 数组的
值由小到大排列。
*/
time = 0;
y = 0;
for (i = TIMES / 6; i < TIMES*5/6; i++)
{
y += data[i];
}
/*
把刚才转换后的第10 次~49 次的值相加,存放到变量y 中,其实就是40
次转换的结果相加。
*/
y /= (TIMES*2/3);
/*
把刚才转换的结果除以40,得到本次转换的最终结果。
*/
y &= 0x3ff;
if (cheat < 400)
{
for (i = 0; i < CHEAT_NUMBER; i++)
{
if (y > cheat_y[i])
{
cheat_diff_y = y - cheat_y[i];
}
else
{
cheat_diff_y = cheat_y[i] - y;
}
if (cheat_diff_y < 20)
{
y = cheat_y[i];
break;
}
else if (cheat_y[i] == 0)
{
cheat_y[i] = y;
break;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: