📄 touch.c
字号:
/* * s3c44b0-ts.c * * touchScreen driver for SAMSUNG S3C44B0 * * Author: vencent <zlg@qhkj.com> * Date : $Date: 2003/12/17 07:11:00 $ * * * Based on s3c44b0-ts.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. * * History: * * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>//#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/wait.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/segment.h>#include <asm/system.h>#include <asm/byteorder.h>#include <asm/unaligned.h>#include <asm/arch/irqs.h>#include <asm/arch/hardware.h>//#include "sio.h"#define PEN_UP 0 #define PEN_DOWN 1#define PEN_FLEETING 2#define MAX_TS_BUF 2 /* how many do we want to buffer */#define DEVICE_NAME "ts"#define TSRAW_MINOR 1typedef struct { unsigned short pressure; unsigned short x; unsigned short y; unsigned short pad;} TS_RET;typedef struct { unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_FLEETING */ TS_RET buf[MAX_TS_BUF]; /* protect against overrun */ //unsigned int head = 0, tail = 1; /* head and tail for queued events */ wait_queue_head_t wq; spinlock_t lock;} TS_DEV;static TS_DEV tsdev;static unsigned short EDGE_X_MIN=0;static unsigned short EDGE_Y_MIN=0;static unsigned short EDGE_X_MAX=4096;static unsigned short EDGE_Y_MAX=4096;static unsigned short SCREEN_X=320;static unsigned short SCREEN_Y=240;#define IRQ_TC S3C44B0X_INTERRUPT_EINT2#define ADS7843_PIN_CS (1<<6) //GPF6#define ADS7843_PIN_CLK (1<<8) //GPF8#define ADS7843_PIN_DIN (1<<5) //GPF5#define ADS7843_PIN_DOUT (1<<7) //GPF7#define ADS7843_PIN_PEN (1<<2) // GPG2/EXINT2//控制字各位定义#define ADS7843_START_BIT (1<<0) #define ADS7843_A2 (1<<1) #define ADS7843_A1 (1<<2) #define ADS7843_A0 (1<<3) #define ADS7843_MODE (1<<4) #define ADS7843_SER_DFR (1<<5) #define ADS7843_PD1 (1<<6) #define ADS7843_PD0 (1<<7) /* Ask for X conversion enable PENIRQ */#define ADS7843_ASKX (ADS7843_START_BIT | \ ADS7843_A2 | \ ADS7843_A1 *0| \ ADS7843_A0 | \ ADS7843_MODE *0| \ ADS7843_SER_DFR *0| \ ADS7843_PD1 *0| \ ADS7843_PD0 *0) /* Ask for Y conversion enable PENIRQ */#define ADS7843_ASKY (ADS7843_START_BIT | \ ADS7843_A2 *0 | \ ADS7843_A1 *0| \ ADS7843_A0 | \ ADS7843_MODE *0| \ ADS7843_SER_DFR*0 | \ ADS7843_PD1 *0| \ ADS7843_PD0 *0)/*Enable PENIRQ*/#define ADS7843_NOP (ADS7843_START_BIT | \ ADS7843_A2 *0 | \ ADS7843_A1 *0| \ ADS7843_A0 *0| \ ADS7843_MODE *0| \ ADS7843_SER_DFR *0| \ ADS7843_PD1 *0| \ ADS7843_PD0 *0)//#define BUF_HEAD (tsdev.buf[tsdev.head])//#define BUF_TAIL (tsdev.buf[tsdev.tail])#define BUF_HEAD (tsdev.buf[0])#define BUF_TAIL (tsdev.buf[1])//#define INCBUF(x,mod) ((++(x)) & ((mod) - 1))static int tsMajor = 10;static void (*tsEvent)(void);#define HOOK_FOR_DRAG#ifdef HOOK_FOR_DRAG#define TS_TIMER_DELAY (HZ/10) /* 100 ms */#define TS_TIMER_DELAY1 (HZ/20) /* 5 ms */static struct timer_list ts_timer;#endif#define HOLDING_TIME 50 // 50us// Write ads7843 control command void ads7843_din(char command){ int i; for(i = 0; i < 8; i++,command>>=1) { outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->1 if( command & 0x01 ) outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_DIN), S3C44B0X_PDATF); //DIN->1 else outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_DIN), S3C44B0X_PDATF); //DIN->0 udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->0 udelay(HOLDING_TIME); }}//测量X static int s3c44b0_ts_measure_x(void){ char i; int touch_data = 0; outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CS|ADS7843_PIN_CLK), S3C44B0X_PDATF); // CS,CLK->0 ads7843_din( ADS7843_ASKX ); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK|ADS7843_PIN_DIN), S3C44B0X_PDATF); // CLK,DIN->0 udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->1 // while(!(inl(S3C44B0X_PDATF) & ADS7843_BUSY)); udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->0 udelay(HOLDING_TIME); for(i = 0; i < 15; i++,touch_data <<= 1) { outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->1 if(inl(S3C44B0X_PDATF) & ADS7843_PIN_DOUT) touch_data |= 0x01; else touch_data &= ~(0x01); udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->0 udelay(HOLDING_TIME); } outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CS), S3C44B0X_PDATF); // CS->1 touch_data >>= 3; return (touch_data & 0xfff); } //测量Y static int s3c44b0_ts_measure_y(void){ char i; int touch_data = 0; outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CS|ADS7843_PIN_CLK), S3C44B0X_PDATF); // CS,CLK->0 ads7843_din( ADS7843_ASKY ); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK|ADS7843_PIN_DIN), S3C44B0X_PDATF); // CLK,DIN->0 udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->1 // while(!(inl(S3C44B0X_PDATF) & ADS7843_BUSY)); udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->0 udelay(HOLDING_TIME); for(i = 0; i < 15; i++,touch_data <<= 1) { outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->1 if(inl(S3C44B0X_PDATF) & ADS7843_PIN_DOUT) touch_data |= 0x01; else touch_data &= ~(0x01); udelay(HOLDING_TIME); outl(inl(S3C44B0X_PDATF)&~(ADS7843_PIN_CLK), S3C44B0X_PDATF); // CLK->0 udelay(HOLDING_TIME); } outl(inl(S3C44B0X_PDATF)|(ADS7843_PIN_CS), S3C44B0X_PDATF); // CS->1 touch_data >>= 3; return (touch_data & 0xfff); }static int x, y; /* touch screen coorinates */static void tsEvent_raw(void){ if (tsdev.penStatus == PEN_DOWN || tsdev.penStatus == PEN_FLEETING) { BUF_HEAD.x = BUF_TAIL.x; BUF_HEAD.y = BUF_TAIL.y; BUF_HEAD.pressure = tsdev.penStatus; } else { BUF_HEAD.x = 0; BUF_HEAD.y = 0; BUF_HEAD.pressure = PEN_UP; } //tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF); wake_up_interruptible(&(tsdev.wq));}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)); // printk("BUF_TAIL.x = %d, BUF_TAIL.y = %d\n",ts_ret->x,ts_ret->y); return sizeof(TS_RET);}/*static ssize_t s3c44b0_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; } return sizeof(TS_RET);}*/static ssize_t s3c44b0_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ int count; TS_RET ts_ret; //if (tsdev.head == tsdev.tail) //if ((BUF_HEAD.x != BUF_TAIL.x) && (BUF_HEAD.y != BUF_TAIL.y)) if ((BUF_TAIL.x == 0) && (BUF_TAIL.y == 0)) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&(tsdev.wq)); if (signal_pending(current)) return -ERESTARTSYS; } count = tsRead(&ts_ret); if (count) copy_to_user(buffer, (char *)&ts_ret, count); return count; } static unsigned int s3c44b0_ts_poll(struct file *filp, struct poll_table_struct *wait){ poll_wait(filp, &(tsdev.wq), wait); //if (tsdev.head != tsdev.tail) //if ((BUF_HEAD.x != BUF_TAIL.x) && (BUF_HEAD.y != BUF_TAIL.y)) if ((BUF_TAIL.x == 0) && (BUF_TAIL.y == 0)) return (POLLIN | POLLRDNORM); return 0;}static void s3c44b0_isr_tc(int irq, void *dev_id, struct pt_regs *reg){ //spin_lock_irq(&(tsdev.lock)); //DPRINTK("Occured Touch Screen Interrupt\n"); if ((tsdev.penStatus == PEN_UP)) { int i; //PCONG &= ~(3<<10); //into input mode //TS_CLOSE_INT(); //disable_irq(IRQ_TC); //udelay(1); if ((inl(S3C44B0X_PDATG) & ADS7843_PIN_PEN)==0) { tsdev.penStatus = PEN_DOWN;#ifdef HOOK_FOR_DRAG //ts_timer.expires = jiffies + TS_TIMER_DELAY1; ts_timer.expires = jiffies + TS_TIMER_DELAY; add_timer(&ts_timer);#endif } else{ //PCONG |= (3<<10); //into EXINT mode //enable_irq(IRQ_TC); //outl((0x01)<<23, S3C44B0X_I_ISPC); } } //spin_unlock_irq(&(tsdev.lock)); outl((0x01)<<23, S3C44B0X_I_ISPC); }#ifdef HOOK_FOR_DRAGstatic void ts_timer_handler(unsigned long data){ //spin_lock_irq(&(tsdev.lock)); if ((inl(S3C44B0X_PDATG)&ADS7843_PIN_PEN)==0) { //s3c44b0_get_XY(); //if(tsdev.penStatus == PEN_DOWN) BUF_TAIL.x = s3c44b0_ts_measure_x(); BUF_TAIL.y = s3c44b0_ts_measure_y(); tsdev.penStatus = PEN_FLEETING;#ifdef HOOK_FOR_DRAG ts_timer.expires = jiffies + TS_TIMER_DELAY; add_timer(&ts_timer);#endif } else{ tsdev.penStatus = PEN_UP; del_timer(&ts_timer); tsEvent(); //enable_irq(IRQ_TC); } //spin_unlock_irq(&(tsdev.lock)); //outl((0x01)<<23, S3C44B0X_I_ISPC); }#endifstatic int s3c44b0_ts_open(struct inode *inode, struct file *filp){ int ret; ret = request_irq(IRQ_TC, s3c44b0_isr_tc, 0, DEVICE_NAME, NULL); if(ret < 0) { printk("TouchPanel Driver: Error while installing IRQ_TC handler.\n"); return -ENODEV; } else { // printk("The TouchPanel is registered successfully!\n"); //printk("ret = %d \n", ret); } outl(inl(S3C44B0X_PCONG)|((0x03)<<4), S3C44B0X_PCONG); outl(inl(S3C44B0X_INTMOD)&(~(0x1<<23)), S3C44B0X_INTMOD); outl(inl(S3C44B0X_EXTINT)&(~((0x7)<<8)), S3C44B0X_EXTINT); outl(inl(S3C44B0X_EXTINT)|(0x2<<8), S3C44B0X_EXTINT); outl(inl(S3C44B0X_PCONE)&(0x3cfff), S3C44B0X_PCONE); outl(inl(S3C44B0X_PCONE)|(0x1000), S3C44B0X_PCONE); //PE6 as output outl(inl(S3C44B0X_PUPE)&(0x1bf), S3C44B0X_PUPE); outl(inl(S3C44B0X_PDATE)|(0x40), S3C44B0X_PDATE); /* PE6->1 Disable I/O expand in CPLD */ disable_irq(IRQ_TC); //tsdev.head = tsdev.tail = 0; tsdev.penStatus = PEN_UP;#ifdef HOOK_FOR_DRAG init_timer(&ts_timer); ts_timer.function = ts_timer_handler;#endif tsEvent = tsEvent_raw; init_waitqueue_head(&(tsdev.wq)); enable_irq(IRQ_TC); MOD_INC_USE_COUNT; return 0;}static int s3c44b0_ts_release(struct inode *inode, struct file *filp){#ifdef HOOK_FOR_DRAG del_timer(&ts_timer);#endif disable_irq(IRQ_TC); free_irq(IRQ_TC, NULL); MOD_DEC_USE_COUNT; return 0;}static struct file_operations s3c44b0ts_fops = { owner: THIS_MODULE, open: s3c44b0_ts_open, read: s3c44b0_ts_read, release: s3c44b0_ts_release, poll: s3c44b0_ts_poll,};void tsEvent_dummy(void) {}void s3c44b0_ts_init(void){ int ret; int flags; tsEvent = tsEvent_dummy; outl(inl(S3C44B0X_PCONF)&(~((0x0fff)<<10)), S3C44B0X_PCONF); outl(inl(S3C44B0X_PCONF)|((0x209)<<10), S3C44B0X_PCONF); outl(inl(S3C44B0X_PUPF)&(0x01f), S3C44B0X_PUPF); outl(inl(S3C44B0X_PUPF)|(0x080), S3C44B0X_PUPF); outl(inl(S3C44B0X_PDATF)&(0x0df), S3C44B0X_PDATF); //PF8,PF5->0 outl(inl(S3C44B0X_PDATF)|(0x040), S3C44B0X_PDATF); //CS/PF6->1 //local_irq_save(flags); /* outl(inl(S3C44B0X_PCONG)|((0x03)<<4), S3C44B0X_PCONG); outl(inl(S3C44B0X_INTMOD)&(0x0<<23), S3C44B0X_INTMOD); outl(inl(S3C44B0X_EXTINT)&(~((0x7)<<8)), S3C44B0X_EXTINT); outl(inl(S3C44B0X_EXTINT)|(0x2<<8), S3C44B0X_EXTINT); */ // local_irq_restore(flags); ret = register_chrdev(tsMajor, DEVICE_NAME, &s3c44b0ts_fops); if (ret < 0) { printk("Panic! Could not register TouchPanel Driver.\n"); //return ret; } printk("The TouchPanel is registered successfully!\n"); //local_irq_save(flags); /* Enable touch interrupt *//* ret = request_irq(IRQ_TC, s3c44b0_isr_tc, 0, DEVICE_NAME, NULL); if(ret < 0) { printk("TouchPanel Driver: Error while installing IRQ_TC handler.\n"); //return -ENODEV; } else { printk("The TouchPanel is registered successfully!\n"); //printk("ret = %d \n", ret); } disable_irq(IRQ_TC); //udelay(10); //local_irq_restore(flags);*/ return;}static void s3c44b0_ts_exit(void){ unregister_chrdev(tsMajor, DEVICE_NAME); //free_irq(IRQ_TC, NULL);}//module_init(s3c44b0_ts_init);//module_exit(s3c44b0_ts_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -