📄 linux下的触摸屏驱动源码.txt
字号:
*
***************************************
* 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 <linux/queue.h> /*任务队列*/
#include <asm/uaccess.h>
#include <asm/arch-S3C44B0X/s3c44b0x.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch-S3C44B0X/irqs.h>
#define TOUCH_MAJOR 10
#define TOUCH_DEVNAME "touchscreen_kmf"
#define TS_IRQ S3C44B0X_INTERRUPT_EINT3
//#define MAX_TS_BUF 16 //校准用
/*第一次轮询时间*/
static int FirstPollDelay=2;
static int PollDelay = 10;
static int touch_initialized;
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 xres = 640;
static int yres = 240;
// A/D 通道选择命令字和工作寄存器
#define CHX 0x90 //通道Y+的选择控制字 //0x94
#define CHY 0xD0 //通道X+的选择控制字 //0xD4
#define TP_DCLK(a) outw((inw(S3C44B0X_PDATF) &(~(1<<8)) ) | ((a&1)<<8),S3C44B0X_PDATF) //----GPF8
#define TP_CS(a) outw((inw(S3C44B0X_PDATF) &(~(1<<7)) ) | ((a&1)<<7),S3C44B0X_PDATF) //-----GPF7
#define TP_DIN(a) outw((inw(S3C44B0X_PDATF) &(~(1<<6)) ) | ((a&1)<<6),S3C44B0X_PDATF) //------GPF6
//读ADS7843的IO控制口
//#define TP_BUSY
#define TP_DOUT ((inw(S3C44B0X_PDATF)>>5) & 0x1) //-------GPF5
#define TP_IRQ ((inb(S3C44B0X_PDATG)>>3) & 0x1) //TP_IRQ--------ExINT3(GPG3)
/*打算在中断中使用定时器队列,定义定时器链表*/
static struct timer_list touch_timer; /* be used for polling */
//struct wait_queue *wq = NULL; /* global variable */
DECLARE_WAIT_QUEUE_HEAD(touch_wait); /*等同于 struct wait_queue *touch_wait= NULL*/
static struct TS_RET
{
unsigned short pressure;//!< zero -> not pressed, all other values indicate that the touch is pressed
unsigned short x; //The x position
unsigned short y;//The y position
}touchstat={0,0,0};
static void ads7843_Start( void )
{
TP_DCLK(0);
TP_CS(1);
TP_DIN(1);
TP_DCLK(1);
TP_CS(0); //芯片允许
}
static void ads7843_Write ( unsigned char cmd )
{
unsigned char buf, i, j ;
TP_DCLK(0);
for( i = 0; i < 8; i++ )
{
buf = (cmd >> (7-i)) & 0x1 ; //MSB在前,LSB在后
TP_DIN(buf); //时钟上升沿锁存DIN
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(1); //开始发送命令字
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(0); //时钟脉冲,一共8个
}
}
static unsigned short ads7843_Read ( void )
{
unsigned short buf = 0 ;
unsigned char i, j ;
for( i = 0; i < 12; i++ )
{
buf = buf << 1 ;
TP_DCLK(1);
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(0);
for( j = 0; j < 5; j++ ); //时钟下降沿读取,一共12个,MSB在前,LSB在后
if ( TP_DOUT ) buf = buf + 1 ;
for( j = 0; j < 20; j++ ); //200ns
}
/*
for( i = 0; i < 4; i++ )
{
TP_DCLK(1);
for( j = 0; j < 25; j++ ); //200ns
TP_DCLK(0);
for( j = 0; j < 25; j++ ); //4个没用时钟
}
*/
return( buf ) ;
}
static void ads7843_port_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);
outw((val16&0xFFDF), S3C44B0X_PUPF); /* config GPF5 activate pull up GPF5 上拉电阻使能*/
}
static void ads7843_get_XY(void)
{
unsigned short j ;
ads7843_Start() ;
for( j = 0; j < 5; j++ ); //40ns
//while ( TP_BUSY ) ; //如果BUSY,等待直到转换完毕,这个可以不用
ads7843_Write( CHX ) ;
for( j = 0; j < 25; j++ ); //200ns
touchstat.x= ads7843_Read() ;
ads7843_Write( CHY ) ;
for( j = 0; j < 25; j++ ); //200ns
touchstat.y = ads7843_Read() ;
}
void touch_poll_task (unsigned long irq) /*中断程序下半部*/
{
/*配置PCNOG 将GPG3设为输入模式,供轮询*/
outw(inw(S3C44B0X_PCONG)&0xFF3F, S3C44B0X_PCONG);
/*读入GPG3脚(触摸屏当前)状态*/
touchstat.pressure=TP_IRQ;
/*获取X , Y 坐标*/
ads7843_get_XY();
/*触摸屏仍然被按下, 继续轮询*/
if(touchstat.pressure==1)
{
init_timer(&touch_timer);
touch_timer.function = touch_poll_task;
touch_timer.data = irq;
touch_timer.expires = PollDelay;
add_timer(&touch_timer);
}
else
{
/*-------------------------*/
/* enable irq */
/*-------------------------*/
touchstat.pressure=0;
touch_event=1;
outw( inw(S3C44B0X_PCONG)|0xC0, S3C44B0X_PCONG); /*重新配置PCNOG 将GPG3设为中断模式*/
enable_irq(irq);
return;
}
wake_up_interruptible(&touch_wait); /* wake any reading process */
}
static void touch_interrupt(int irq, void *dev_id, struct pt_regs *regs) /*中断程序上半部*/
{
/*-------------------------*/
/* disable irq */
/*-------------------------*/
disable_irq(irq);
touchstat.pressure=1; /*表示按下状态*/
/*-------------------------*/
/* setup kernel timer */
/*-------------------------*/
init_timer(&touch_timer);
touch_timer.function = touch_poll_task;
touch_timer.data = irq;
touch_timer.expires = FirstPollDelay;
add_timer(&touch_timer);
/*--------------------------*/
/* return from interrupt */
/*--------------------------*/
return;
}
static ssize_t touchscreen_read(struct file *file, char *buffer,
size_t count, loff_t *pos)
{
int count=2;
unsigned short XYret[2];
while (!touch_event)
{
interruptible_sleep_on( &touch_wait);
}
XYret[0]=touchstat.x;
XYret[1]=touchstat.y;
if(copy_to_user(buffer, XYret, count))
return -EFAULT;
touch_event = 0;
return count;
}
static unsigned int touchscreen_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &touch_wait, 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;
enable_irq(TS_IRQ);
return 0;
}
static int touchscreen_close(struct inode * inode, struct file * file)
{
touch_users--;
if(!touch_users) /* must be also true since we allow only one user */
disable_irq(TS_IRQ);
return 0;
}
struct file_operations ts_fops = {
read: touchscreen_read,
poll: touchscreen_poll, //查询设备
open: touchscreen_open,
release: touchscreen_close, //释放设备
};
int s3c44b0x_ts_init(void)
{
int result;
unsigned int val32;
unsigned short val16;
printk("s3c44b0x_touch: initializing...\n");
touch_initialized = 0;
TP_CS(1);/*ads7843芯片禁止*/
ads7843_port_init();
/*-------------------------------*/
/* configure interrupt */
/*-------------------------------*/
val32=inl(S3C44B0X_INTMOD);
outl((val32&0xFBFFFFF), S3C44B0X_INTMOD); /* normal IRQ */
val32=inl(S3C44B0X_EXTINT);
outl((val32&0xFFFF8FFF)|0x2000, S3C44B0X_EXTINT); /*falling edge 下降沿触发*/
val16 =inw(S3C44B0X_PCONG);
outw(val16 | 0xC0, S3C44B0X_PCONG); /* use Port G pin 3 as ext int 3 */
ads7843_Start(); // ADS7843 芯片允许
if((result = register_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ,&ts_fops))<0)
{
printk("touch_rw. unable to get major %d for led write\n", TOUCH_MAJOR);
return result;
}
if(request_irq(TS_IRQ, touch_interrupt, 0, "44b0_touchscreen",NULL))
{
printk("s3c44b0: unable to get IRQ\n");
return -EBUSY;
}
touch_initialized ++;
return 0;
}
int s3c44b0x_ts_exit(void)
{
int result;
if (touch_initialized >= 1)
{
if((result = unregister_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ))<0)
printk("TOUCH DEV. unable to release major %d for read \n",TOUCH_MAJOR);
return result;
}
free_irq(TS_IRQ, NULL);
printk(KERN_INFO "touchscreen uninstalled\n");
touch_initialized --;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -