📄 snts46_ts.c
字号:
#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include "snts46_ts.h"
#define PRINTK printk
#define DELAY 30
static int head, tail;
int int_num=0;
static TS_EVENT cur_data, samples[3], buf[BUFSIZE];
static struct fasync_struct *fasync;
static unsigned long in_timehandle = 0;
unsigned int count =0;
static void ts_clear(void);
static void print_par(void);
static void read_xy(void);
void ads7843_askx(void)
{
SSDR = DIFFMODE_X_POSI;
}
void ads7843_asky(void)
{
SSDR = DIFFMODE_Y_POSI;
}
void ads7843_nop(void)
{
SSDR = SPIMDATA_NOP;
}
int sa1100_ts_measure_x(void)
{
char i;
int touch_data = 0;
udelay(DELAY);
SSDR = DIFFMODE_X_POSI;
udelay(DELAY);
touch_data =SSDR;
return (touch_data);
}
int sa1100_ts_measure_y(void)
{
char i;
int touch_data = 0;
udelay(DELAY);
SSDR = DIFFMODE_Y_POSI;
udelay(DELAY);
touch_data =SSDR;
return (touch_data);
}
void Ads7843_Enable_IRQ(void)
{
udelay(DELAY);
ads7843_nop();
udelay(DELAY);
}
static int ads7843_ts_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
/* Microwindows style (should change to TS_CAL when the specification is ready) */
switch (cmd)
{
case 3:
raw_max_x = arg;
break;
case 4:
raw_max_y = arg;
break;
case 5:
res_x = arg;
break;
case 6:
res_y = arg;
break;
case 10:
raw_min_x = arg;
break;
case 11:
raw_min_y = arg;
break;
case 12:
/* New attribute for portrait modes */
xyswap = arg;
/* Allen Add */
case 13: /* 0 = Enable calibration ; 1 = Calibration OK */
cal_ok = arg;
case 14: /* Clear all buffer data */
ts_clear();
break;
case 15: /* X axis reversed setting */
x_rev = arg;
break;
case 16: /* Y axis reversed setting */
y_rev = arg;
break;
case 17: /* Clear all buffer data */
print_par();
break;
/* Allen */
}
return 0;
}
static void ts_clear(void)
{
int i;
for (i=0; i < BUFSIZE; i++)
{
buf[i].pressure=(short)NULL;
buf[i].x=(int)NULL;
buf[i].y=(int)NULL;
buf[i].millisecs=(int)NULL;
}
head = 0;
tail = 0;
}
static void print_par(void)
{
printk(" Kernel ==> cal_ok = %d\n",cal_ok);
printk(" Kernel ==> raw_max_x = %d\n",raw_max_x);
printk(" Kernel ==> raw_max_y = %d\n",raw_max_y);
printk(" Kernel ==> res_x = %d\n",res_x);
printk(" Kernel ==> res_y = %d\n",res_y);
printk(" Kernel ==> raw_min_x = %d\n",raw_min_x);
printk(" Kernel ==> raw_min_y = %d\n",raw_min_y);
printk(" Kernel ==> xyswap = %d\n",xyswap);
printk(" Kernel ==> x_rev = %d\n",x_rev);
printk(" Kernel ==> y_rev = %d\n",y_rev);
}
static void new_data(void)
{
static TS_EVENT last_data = { 0, 0, 0, 0 };
static TS_EVENT temp_data[2];
int diff0, diff1, diff2, diff3=0;
if (cur_data.pressure)
{
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)
{
// printk("1\r\n");
return;
}
if (diff0 < diff1)
{
if (diff2 < diff0)
temp_data[0].x = (samples[0].x + samples[2].x) / 2;
else
temp_data[0].x = (samples[0].x + samples[1].x) / 2;
}
else
{
if (diff2 < diff3)
temp_data[0].x = (samples[2].x + samples[0].x) / 2;
else
temp_data[0].x = (samples[2].x + samples[1].x) / 2;
}
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 || diff3 > YLIMIT)
{
// printk("2\r\n");
return;
}
if (diff0 < diff2)
{
if (diff2 < diff3)
temp_data[0].y = (samples[0].y + samples[2].y) / 2;
else
temp_data[0].y = (samples[0].y + samples[1].y) / 2;
}
else
{
if (diff2 < diff3)
temp_data[0].y = (samples[2].y + samples[0].y) / 2;
else
temp_data[0].y = (samples[2].y + samples[1].y) / 2;
}
if(!last_data.x && !last_data.y)
{
last_data = temp_data[0];
temp_data[1] = temp_data[0];
// printk("3\r\n");
return;
}
cur_data.x = last_data.x;
cur_data.y = last_data.y;
last_data = temp_data[1];
temp_data[1] = temp_data[0];
}
else
{
/* Reset jitter detection on pen release */
last_data.x = 0;
last_data.y = 0;
}
cur_data.millisecs = jiffies;
if (head != tail)
{
int last = head--;
if (last < 0)
last = BUFSIZE - 1;
}
buf[head] = cur_data;
if (++head == BUFSIZE)
head = 0;
if (head == tail && tail++ == BUFSIZE)
tail = 0;
if (fasync)
kill_fasync(&fasync, SIGIO, POLL_IN);
printk("X = %d, Y = %d \n",cur_data.x, cur_data.y);
wake_up_interruptible(&queue);
}
static TS_EVENT get_data(void)
{
int last = tail;
if (++tail == BUFSIZE)
tail = 0;
return buf[last];
}
static void wait_for_action(void)
{
set_GPIO_IRQ_edge(IRQ_GPIO_SNTS46, GPIO_FALLING_EDGE);
//set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_GPIO_SNTS46), GPIO_FALLING_EDGE);
enable_irq(IRQ_GPIO_SNTS46);
}
static unsigned int ads7843_ts_poll(struct file *filp, poll_table *wait)
{
poll_wait(filp, &queue, wait);
if (head != tail)
return POLLIN | POLLRDNORM;
return 0;
}
static ssize_t ads7843_ts_read(struct file *filp, char *buf, size_t count, loff_t *l)
{
DECLARE_WAITQUEUE(wait, current);
int i;
TS_EVENT t;
short out_buf[4];
short tmp;
if (head == tail)
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
add_wait_queue(&queue, &wait);
current->state = TASK_INTERRUPTIBLE;
while ((head == tail) && !signal_pending(current))
{
schedule();
current->state = TASK_INTERRUPTIBLE;
}
current->state = TASK_RUNNING;
remove_wait_queue(&queue, &wait);
}
for (i = count; i >= sizeof(out_buf); i -= sizeof(out_buf), buf += sizeof(out_buf))
{
if (head == tail)
break;
t = get_data();
out_buf[0] = t.pressure;
if(xyswap) {
tmp = t.y;
t.y = t.x;
t.x = tmp;
}
if (cal_ok)
{
out_buf[1] = (x_rev) ? ((raw_max_x - t.x) * res_x) / (raw_max_x - raw_min_x) :
((t.x - raw_min_x) * res_x) / (raw_max_x - raw_min_x);
out_buf[2] = (y_rev) ? ((raw_max_y - t.y) * res_y) / (raw_max_y - raw_min_y) :
((t.y - raw_min_y) * res_y) / (raw_max_y - raw_min_y);
out_buf[1] = out_buf[1] < res_x ? out_buf[1] : res_x - 1;
out_buf[2] = out_buf[2] < res_y ? out_buf[2] : res_y - 1;
out_buf[1] = out_buf[1] >= 0 ? out_buf[1] : 0;
out_buf[2] = out_buf[2] >= 0 ? out_buf[2] : 0;
}
else
{
out_buf[1] = t.y;
out_buf[2] = t.x;
}
out_buf[3] = t.millisecs;
copy_to_user(buf, &out_buf, sizeof(out_buf));
}
return count - i;
}
static void ads7843_ts_timer(unsigned long);
static int ads7843_ts_starttimer(void)
{
in_timehandle++;
init_timer(&timer);
timer.function = ads7843_ts_timer;
timer.expires = jiffies + HZ / 100;
add_timer(&timer);
return 0;
}
static void ads7843_ts_timer(unsigned long data)
{
in_timehandle--;
if ((GPLR0 & GPIO_bit(snts46_PENIRQ))) { //没有中断
printk("PEN_UP\r\n");
cur_data.pressure = 0;
new_data();
wait_for_action();
}
else //有中断
{
if(samples[0].x!=0 || samples[1].x!=0 || samples[2].x!=0)
read_xy();
printk("PEN_DOWN\r\n");
}
}
static void read_xy(void)
{
disable_irq(IRQ_GPIO_SNTS46);
ads7843_askx();
udelay(200);
ads7843_asky();
samples[0].x = sa1100_ts_measure_x();
samples[0].y = sa1100_ts_measure_y();
samples[1].x = sa1100_ts_measure_x();
samples[1].y = sa1100_ts_measure_y();
samples[2].x = sa1100_ts_measure_x();
samples[2].y = sa1100_ts_measure_y();
cur_data.pressure = 1;
new_data();
// enable_irq(IRQ_GPIO_SNTS46);
ads7843_ts_starttimer();
}
static int ads7843_ts_fasync(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &fasync);
if (retval < 0)
return retval;
return 0;
}
static int ads7843_ts_open(struct inode *inode, struct file *filp)
{
ts_clear();
MOD_INC_USE_COUNT;
return 0;
}
static int ads7843_ts_release(struct inode *inode, struct file *filp)
{
ts_clear();
ads7843_ts_fasync(-1, filp, 0);
MOD_DEC_USE_COUNT;
return 0;
}
static void ads7843_ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int_num ++;
if (in_timehandle > 0)
return;
if(int_num<3)
return;
// printk("Interrupt come\r\n");
read_xy();
}
static struct file_operations ads7843_ts_fops = {
read: ads7843_ts_read,
poll: ads7843_ts_poll,
ioctl: ads7843_ts_ioctl,
fasync: ads7843_ts_fasync,
open: ads7843_ts_open,
release:ads7843_ts_release,
};
int sa1100_ts_init(void)
{
raw_max_x = 965;
raw_max_y = 970;
raw_min_x = 23;
raw_min_y = 45;
res_x =640;
res_y =480;
xyswap = 0;
head = 0;
tail = 0;
cal_ok = 1;
x_rev = 0;
y_rev = 1;
init_waitqueue_head(&queue);
ts_clear();
wait_for_action();
return 0;
}
static devfs_handle_t devfs_handle, devfs_ts_dir;
int __init ads7843_ts_init(void)
{
int ret;
set_GPIO_mode(GPIO23_SCLK_MD);
set_GPIO_mode(GPIO24_SFRM_MD);
set_GPIO_mode(GPIO25_STXD_MD);
set_GPIO_mode(GPIO26_SRXD_MD);
set_GPIO_mode(GPIO27_EXTCLK_MD);
set_GPIO_mode(GPIO9_GEN_MD);
GPDR0 = 0xC3CB9130;
/*
printk("\nsnts46_ts:set the mode of GPIO.\n");
printk("GAFR0_U:ox%x\n",GAFR0_U);
printk("GAFR0_L:ox%x\n",GAFR0_L);
printk("GPLR0:ox%x\n",GPLR0);
printk("GPDR0:ox%x\n",GPDR0);
*/
SSCR0 = 0x0000472B;
SSCR1 =0x00000440;
CKEN |= CKEN3_SSP;
SSCR0 |= 0x00000080; //SSP operation enabled
if ((ret=devfs_register_chrdev(TS_MAJOR, TS_NAME, &ads7843_ts_fops))!=0)
{
printk("registering of " TS_NAME " is failed\n");
return ret;
}
devfs_ts_dir = devfs_mk_dir(NULL, "touchscreen", NULL);
devfs_handle = devfs_register(devfs_ts_dir, "0raw",
DEVFS_FL_DEFAULT,
TS_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&ads7843_ts_fops, NULL);
if ((ret = request_irq(IRQ_GPIO_SNTS46, ads7843_ts_interrupt,
SA_SHIRQ|SA_INTERRUPT, TS_NAME, dev_id)))
{
printk("ads7843_ts_init: failed to register IRQ\n");
free_irq(IRQ_GPIO_SNTS46, dev_id);
return ret;
}
if ((ret = sa1100_ts_init()) != 0)
{
free_irq(IRQ_GPIO_SNTS46, dev_id);
return ret;
}
Ads7843_Enable_IRQ();
printk("snts46 touch screen driver by kiki\n");
return 0;
}
void __exit ads7843_ts_cleanup(void)
{
if (in_timehandle)
del_timer(&timer);
free_irq(IRQ_GPIO_SNTS46, dev_id);
devfs_unregister_chrdev(TS_MAJOR, TS_NAME);
printk("snts46 touch screen driver removed\n");
}
module_init(ads7843_ts_init);
module_exit(ads7843_ts_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -