?? touchscreen(完善版 +pressure).c
字號:
/*
***************************************
* linux/driver/touch/touchscreen.c
* touchscreen driver for my S3C44b0X board
* copyright by kom118@163.com
***************************************
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/wait.h> /*等待隊列*/
#include <asm/uaccess.h>
#include <asm/arch-S3C44B0X/s3c44b0x.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch-S3C44B0X/irqs.h>
#define TOUCH_MAJOR 67
#define TOUCH_DEVNAME "touchscreen_kmf"
#define TS_IRQ S3C44B0X_INTERRUPT_EINT2
#define TOUCHSTATUS_UP 0
#define TOUCHSTATUS_DOWN 1
#define MASK_BIT(bit) (1<<(bit))
#define BIT_EINT2 (1<<23)
#define MAX_TS_BUF 16 //校準用
#define TOUCH_TIMER_DELAY1 (HZ)/100
static int touch_users = 0; /* number of connected users; only one is allowed */
static int touch_event=0; /* is there an event pending? */
static int j,flags=0;
static unsigned char rtmp=0;
/*該值校正用*/
//static int xres = 640;
//static int yres = 240;
// A/D 通道選擇命令字和工作寄存器
#define CHX 0x90 //通道Y+的選擇控制字 //0x9c 0x94
#define CHY 0xD0 //通道X+的選擇控制字 //0xDc 0xD4
#define TP_DCLK(a) outw((inw(S3C44B0X_PDATF) &(~(1<<8)) ) | ((a&1)<<8),S3C44B0X_PDATF) //----GPF8 ,output
#define TP_CS(a) outw((inw(S3C44B0X_PDATF) &(~(1<<7)) ) | ((a&1)<<7),S3C44B0X_PDATF) //-----GPF7 , output
#define TP_DIN(a) outw((inw(S3C44B0X_PDATF) &(~(1<<6)) ) | ((a&1)<<6),S3C44B0X_PDATF) //------GPF6 ,output
//讀ADS7843的I/O控制口
//#define TP_BUSY
#define TP_DOUT ((inw(S3C44B0X_PDATF)>>5) & 0x1) //-------GPF5
#define TP_IRQ ((inb(S3C44B0X_PDATG)>>2) & 0x1) //TP_IRQ--------ExINT2(GPG2)
/*打算在中斷中使用定時器隊列,定義定時器鏈表*/
static struct timer_list touch_timer; /* be used for polling */
struct TS_RET
{
unsigned short p;
unsigned short x; //The x position
unsigned short y;//The y position
} ;
//static struct TS_RET touchstate;
typedef struct {
unsigned int Status; //觸摸屏狀態
struct TS_RET buf[MAX_TS_BUF]; //觸摸屏緩沖區
unsigned int head,tail; //觸摸屏緩沖區頭和尾
wait_queue_head_t wq; //等待隊列
} TS_DEV;
static TS_DEV touchdev;
#define BUF_HEAD touchdev.buf[touchdev.head] //緩沖區頭
#define BUF_TAIL touchdev.buf[touchdev.tail] //緩沖區尾
#define INCBUF(x,mod) ((++(x)) & ((mod)-1)) //移動緩沖區指針
static void (*TouchEvent)(void);
static void TouchEvent_dummy(void) {}
static int IS_DOWN(void);
static void bubble_sort(unsigned short *array, int n)/*采用冒泡排序*/
{
int j, k, h;
unsigned short temp;
for (h=n-1; h>0; h=k) /*循環到沒有比較范圍*/
{
for (j=0, k=0; j<h; j++) /*每次預置k=0,循環掃描后更新k*/
{
if (*(array+j) > *(array+j+1)) /*大的放在后面,小的放到前面*/
{
temp= *(array+j);
*(array+j) = *(array+j+1);
*(array+j+1) =temp; /*完成交換*/
k = j; /*保存最后下沉的位置。這樣k后面的都是排序排好了的。*/
}
}
}
}
static void ads7843_Start( void )
{
TP_CS(1);
TP_DCLK(0);
TP_CS(0);
TP_DIN(1);
//TP_DCLK(1);
}
static void ads7843_Write ( unsigned char cmd )/*實際上寫命令字*/
{
unsigned char i,temp;
temp=0x80;
//printk("TP_DCLK=");
// TP_DCLK(0);
for( j = 0; j < 5; j++ ); //Tcss-Tds
for( i = 0; i < 8; i++ )
{
/*將控制字分解成位傳入ads7843,從而ads7843發送命令*/
if(cmd&temp)
TP_DIN(1);
else
TP_DIN(0);
for( j = 0; j < 15; j++ );
/*軟件模擬一個CLK,將一位送出,總共送8位,所以總共循環產生了8格時鐘*/
TP_DCLK(1); /*DCLK置高*/
for( j = 0; j < 10; j++ ); //200ns
TP_DCLK(0); /*DCLK清0*/
for( j = 0; j < 25; j++ ); //200ns
//為送下一位準備
temp=temp>>1;
}
TP_DIN(0); /*DIN清0,準備讀數據了*/
/*接下來可以讀數據了,直接調用ads7843_read()函數*/
return ;
}
/*讀數據*/
static unsigned short ads7843_Read ( void )
{
unsigned short ack = 0 ;
unsigned char i;
for( i = 0; i < 11; i++ )
{
TP_DCLK(1);
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(0);
for( j = 0; j < 10; j++ ); /*時鐘下降沿讀取*/
if(TP_DOUT)
ack +=1;
for( j = 0; j < 15; j++ ); //120ns
ack=ack<<1;
}
TP_DCLK(1);
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(0);
for( j = 0; j < 10; j++ ); //80ns
//接收最后一位,第12位
if(TP_DOUT)
ack +=1;
for( j = 0; j < 15; j++ );
for( i = 0; i < 4; i++ )
{
TP_DCLK(1);
for( j = 0; j < 25; j++ ); //200 ns
TP_DCLK(0);
for( j = 0; j < 25; j++ );
}
//最后將~CS 置高,ads7843禁止
TP_CS(1);
return ack;
}
static void ads7843_get_XY(void)
{
int sum,i;
unsigned short tempx,tempy,val[20];
sum=0;
/*----------------X 坐標與讀取處理---------------*/
for(i=0;i<20;i++)
{
ads7843_Start() ;
for( j = 0; j < 5; j++ ); //40ns
ads7843_Write(CHX) ;
//延時400ns等待數據轉換
for( j = 0; j < 50; j++ ); //200ns
val[i]= ads7843_Read();
for( j = 0; j < 100; j++ );
}
/*對val進行排序*/
bubble_sort(val, 20);
/*采用中值平均濾波發處理數據*/
for(i=3;i<17;i++)
{
sum+=val[i];
}
/*求平均值*/
tempx=(unsigned short)(sum/14);
/*----------------Y 坐標與讀取處理---------------*/
sum=0;
for(i=0;i<20;i++)
{
ads7843_Start() ;
for( j = 0; j < 5; j++ ); //40ns
ads7843_Write(CHY) ;
for( j = 0; j <50; j++ ); //200ns
val[i]= ads7843_Read() ;
for( j = 0; j < 100; j++ );
}
/*對val進行排序*/
bubble_sort(val, 20);
/*采用中值平均濾波發處理數據*/
for(i=3;i<17;i++)
{
sum+=val[i];
}
/*求平均值*/
tempy=(unsigned short)(sum/14);
/*坐標轉換*/
BUF_HEAD.x=(3853-tempx)*640/(3853-264);
BUF_HEAD.y=(tempy-650)*240/(3638-650);
printk("X=%d , Y=%d\n",BUF_HEAD.x,BUF_HEAD.y);
touchdev.tail=INCBUF(touchdev.tail,MAX_TS_BUF);
}
static void s3c44b0_IO_init(void)
{
/*配置與ADS7843 相連的I/O端口 output : PF5,PG3; input:PF6,PF7,PF8 ;ads7843 busy 線沒用*/
unsigned int val32;
unsigned short val16;
/*配置F 端口*/
/*-------------------------*/
/* configuration of PCONF */
/*-------------------------*/
val32=inl(S3C44B0X_PCONF);
outl((val32&0xFFC003FF)|0xFFC923FF, S3C44B0X_PCONF); /* config GPF5 input ; GPF6 GPF7 GPE8 output */
/*-------------------------*/
/* configuration of PUPF */
/*-------------------------*/
val16 =inb(S3C44B0X_PUPF)&0xFFEF;
outw(val16, S3C44B0X_PUPF); /* config GPF5 activate pull up GPF5 上拉電阻使能,GPF6,GPF7,GPF8 disable */
}
static int IS_DOWN(void)
{
rtmp=inb(S3C44B0X_PDATG);
//讀入GPG端口數據,若沒鍵按下,GPG2 為1
if ((rtmp &0x04)==0)
{
//延時一段時間再判斷,延時消除抖動
for( j= 0; j< 5000; j++ ); //10ms
rtmp=inb(S3C44B0X_PDATG);
if ((rtmp&0x04)==0)
{
//確實有鍵按下
touchdev.Status=TOUCHSTATUS_DOWN;
flags=1;
return 1;
}
else
{
return 0;
}
}
return 0;
}
void touch_task_handler (unsigned long irq) /*中斷程序下半部*/
{
//延時10ms后,判斷按鍵狀態
if(IS_DOWN()==1)
{
/*獲取X , Y 坐標*/
ads7843_get_XY();
/*觸摸屏仍然被按下, 繼續輪詢*/
while((rtmp&0x04)==0)
rtmp=inb(S3C44B0X_PDATG);
BUF_HEAD.p=1;
touch_event=1;
wake_up_interruptible(&(touchdev.wq)); /* wake any reading process */
}
//重新將G端口GPG2 設置為中斷模式
outw(inw(S3C44B0X_PCONG)|0x30, S3C44B0X_PCONG);
//開中斷
outl(inl(S3C44B0X_INTMSK)&(~BIT_EINT2),S3C44B0X_INTMSK);
//清中斷請求寄存器
outl(inl(S3C44B0X_I_ISPC)|(BIT_EINT2),S3C44B0X_I_ISPC);
/*-------------------------*/
/* enable irq */
/*-------------------------*/
//enable_irq(irq);
touchdev.Status=TOUCHSTATUS_UP;
return ;
}
static void touch_interrupt(int irq, void *dev_id, struct pt_regs *regs) /*中斷程序上半部*/
{
//關中斷
outl(inl(S3C44B0X_INTMSK)|(BIT_EINT2),S3C44B0X_INTMSK);
//清中斷請求寄存器
outl(inl(S3C44B0X_I_ISPC)|(BIT_EINT2),S3C44B0X_I_ISPC);
for( j= 0; j< 5000; j++ ); //10ms
/*-------------------------*/
/* disable irq */
/*-------------------------*/
//disable_irq(irq);
if (touchdev.Status==TOUCHSTATUS_UP)
{ //printk(KERN_INFO "get in interrupt ...:):)\n");
//設置GPG2為輸入模式
outw(inw(S3C44B0X_PCONG)&0xFFCF,S3C44B0X_PCONG);
//初始化定時器
init_timer(&touch_timer);
touch_timer.function = touch_task_handler;
touch_timer.data = irq;
touch_timer.expires = jiffies+TOUCH_TIMER_DELAY1;
add_timer(&touch_timer);
}
return;
}
static ssize_t touchscreen_read(struct file *file, char *buffer,
size_t count, loff_t *pos)
{
retry:
if (touchdev.head != touchdev.tail) //當前循環隊列中有數據
{
//把數據從內核空間傳送到用戶空間返回
if(copy_to_user(buffer,(struct TS_RET *)&BUF_HEAD,sizeof(struct TS_RET)))
{
printk("error reading, copy_to_user\n");
return -EFAULT;
}
BUF_HEAD.p=0;/* 讀出數據后,按下狀態清楚*/
touchdev.head=INCBUF(touchdev.head,MAX_TS_BUF);
return sizeof(struct TS_RET);
}
else
{
if(file->f_flags & O_NONBLOCK)//若用戶采用非阻塞方式讀取
return -EAGAIN;
// printk("sleep ..... \n");
wait_event_interruptible(touchdev.wq,flags);
flags=0;
//printk("sleep after .....\n");
}
goto retry;
return sizeof(unsigned char) ;
}
static unsigned int touchscreen_poll(struct file *file, poll_table *wait)
{
printk("poll normally !!!\n");
poll_wait(file, &(touchdev.wq), wait);
return (touchdev.head == touchdev.tail) ? 0 : (POLLIN | POLLRDNORM);
/*poll_wait(file, &(touchdev.wq), wait);
if(touch_event)
return (POLLIN | POLLRDNORM); /* readable */
/*return 0;*/
}
static int touchscreen_open(struct inode *inode, struct file *file)
{
if(!touch_users) /* only one user is allowed!! */
touch_users++;
else
return -EBUSY;
//開中斷
outl(inl(S3C44B0X_INTMSK)&(~BIT_EINT2),S3C44B0X_INTMSK);
printk("opened normally :):):):):):)!!!\n");
for( j= 0; j< 10000; j++ );
touchdev.head = touchdev.tail = 0; //清空按鍵動作緩沖區
enable_irq(TS_IRQ);
return 0;
}
static int touchscreen_close(struct inode * inode, struct file * file)
{
TouchEvent = TouchEvent_dummy; //函數指針指向空函數
if(touch_users<1)
{
printk("release touchdevice error\n");
return -ENODEV;
}
touch_users--;
if(!touch_users) /* must be also true since we allow only one user */
{ disable_irq(TS_IRQ);
//關中斷
outl(inl(S3C44B0X_INTMSK)|BIT_EINT2,S3C44B0X_INTMSK);
}
return 0;
}
struct file_operations ts_fops = {
read: touchscreen_read,
open: touchscreen_open,
release: touchscreen_close, //釋放設備
poll: touchscreen_poll, //查詢設備
};
int s3c44b0x_ts_init(void)
{
int ret,val32;
printk("s3c44b0x_touch: initializing...\n");
/*-------------------------------*/
/* configure s3c44b0x I/O */
/* s3c44b0_IO_init(); */
/*-------------------------------*/
s3c44b0_IO_init();
//TP_CS(1);/*ads7843芯片禁止*/
/*-------------------------------*/
/* configure interrupt */
/*-------------------------------*/
// 將多功能端口GPG2設置為中斷模式
outw(inw(S3C44B0X_PCONG)|0x30, S3C44B0X_PCONG);
//INT2上拉使能
outb(inb(S3C44B0X_PUPG)&(0<<2),S3C44B0X_PUPG);
val32=inl(S3C44B0X_EXTINT);
outl((val32&0xFFFFF8FF)|0x200, S3C44B0X_EXTINT); /* 下降沿觸發*/
//設置中斷控制器INTMOD
val32=inl(S3C44B0X_INTMOD);
val32&=~MASK_BIT(23);
outl(val32, S3C44B0X_INTMOD); /* normal IRQ */
//設置中斷控制器INTCON
outb( 0x5,S3C44B0X_INTCON);
//注冊設備
if((ret = register_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ,&ts_fops))<0)
{
printk("touch_rw. unable to get major %d for led write\n", TOUCH_MAJOR);
return ret;
}
//注冊中斷
if(request_irq(TS_IRQ, touch_interrupt,SA_INTERRUPT, "44b0_touchscreen",NULL))
{
printk("s3c44b0: unable to get IRQ\n");
return -EBUSY;
}
touchdev.head = touchdev.tail = 0; //初始化結構體touchdev
touchdev.Status = TOUCHSTATUS_UP;
//初始化等待隊列
init_waitqueue_head(&(touchdev.wq));
return 0;
}
int s3c44b0x_ts_exit(void)
{
int ret;
//注銷中斷
free_irq(TS_IRQ, NULL);
//注銷設備
if((ret = unregister_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ))<0)
printk("TOUCH DEV. unable to release major %d for read \n",TOUCH_MAJOR);
return ret;
printk(KERN_INFO "touchscreen uninstalled\n");
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -