主机:VM - redhat 9.0
开发板:FL2440,linux-2.6.12
arm-linux-gcc:3.4.1
代码中的第90行,若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应,不知什么原因。
#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/device.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/devfs_fs_kernel.h> #include <asm/hardware/clock.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> // YM_SEN输出驱动器使能,XP_SEN,YP_SEN输出驱动器禁止 // S3C2410_ADCTSC_XY_PST(3) -- 手动测量X、Y方向,等待中断模式 // x=0, 将ADCTSC[8]设置为0,即检测笔尖落下中断信号 #define WAIT4INT(x) (((x)<<8) | \ S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \ S3C2410_ADCTSC_XY_PST(3)) /* ADCTSC Register Bits */ #define S3C2410_ADCTSC_YM_SEN (1<<7) #define S3C2410_ADCTSC_YP_SEN (1<<6) #define S3C2410_ADCTSC_XM_SEN (1<<5) #define S3C2410_ADCTSC_XP_SEN (1<<4) #define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) #define S3C2410_ADCTSC_AUTO_PST (1<<2) #define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) /* ADCCON Register Bits */ #define S3C2410_ADCCON_ECFLG (1<<15) #define S3C2410_ADCCON_PRSCEN (1<<14) #define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6) #define S3C2410_ADCCON_PRSCVLMASK (0xFF<<6) #define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3) #define S3C2410_ADCCON_MUXMASK (0x7<<3) #define S3C2410_ADCCON_STDBM (1<<2) #define S3C2410_ADCCON_READ_START (1<<1) #define S3C2410_ADCCON_ENABLE_START (1<<0) #define S3C2410_ADCCON_STARTMASK (0x3<<0) #ifdef S3C2410_ADCCON #undef S3C2410_ADCCON #endif #ifdef S3C2410_ADCTSC #undef S3C2410_ADCTSC #endif #ifdef S3C2410_ADCDLY #undef S3C2410_ADCDLY #endif #ifdef S3C2410_ADCDAT0 #undef S3C2410_ADCDAT0 #endif #ifdef S3C2410_ADCDAT1 #undef S3C2410_ADCDAT1 #endif #ifdef S3C2410_PA_ADC #undef S3C2410_PA_ADC #endif #define S3C2410_PA_ADC (0x58000000) static void __iomem *base_addr; #define S3C2410_ADCCON (base_addr+(0x00)) #define S3C2410_ADCTSC (base_addr+(0x04)) #define S3C2410_ADCDLY (base_addr+(0x08)) #define S3C2410_ADCDAT0 (base_addr+(0x0c)) #define S3C2410_ADCDAT1 (base_addr+(0x10)) #ifdef CONFIG_PM #include <linux/pm.h> #endif // 支持拖拽 // 若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应。 // 可以看到read接口被调用到,不知为何图标没有响应。 #define HOOK_FOR_DRAG //#define DEBUG #ifdef DEBUG #define DPRINTK printk #else #define DPRINTK #endif typedef struct { unsigned short pressure; unsigned short x; unsigned short y; unsigned short pad; } TS_RET; typedef struct { int xscale; int xtrans; int yscale; int ytrans; int xyswap; } TS_CAL; #define PEN_UP 0 #define PEN_DOWN 1 #define PEN_FLEETING 2 #define MAX_TS_BUF 16 /* how many do we want to buffer */ #undef USE_ASYNC #define DEVICE_NAME "s3c2410-ts" #define TSRAW_MINOR 1 typedef struct { unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */ TS_RET buf[MAX_TS_BUF]; /* protect against overrun */ unsigned int head, tail; /* head and tail for queued events */ wait_queue_head_t wq; spinlock_t lock; #ifdef USE_ASYNC struct fasync_struct *aq; #endif #ifdef CONFIG_PM struct pm_dev *pm_dev; #endif } TS_DEV; static TS_DEV tsdev; #define BUF_HEAD (tsdev.buf[tsdev.head]) #define BUF_TAIL (tsdev.buf[tsdev.tail]) #define INCBUF(x,mod) ((++(x)) & ((mod) - 1)) static int tsMajor = 0; static void (*tsEvent)(void); #ifdef HOOK_FOR_DRAG #define TS_TIMER_DELAY (HZ/100) /* 10 ms */ static struct timer_list ts_timer; #endif // pick-up regs val from 2.4.18&2440 // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖落下中断信号,等待中断模式 #define wait_down_int() __raw_writel(0x000000d3,S3C2410_ADCTSC) // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖抬起中断信号,等待中断模式 #define wait_up_int() __raw_writel(0x000001d3, S3C2410_ADCTSC) // XM_SEN、XP_SEN输出驱动器使能,XP上拉禁止,正常ADC转换,X方向测量模式 #define mode_x_axis() __raw_writel(0x00000069, S3C2410_ADCTSC) // 相当于__raw_writel(0x00000068, S3C2410_ADCTSC),即 // XM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,无操作模式 #define mode_x_axis_n() __raw_writel(XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \ XP_PULL_UP_DIS | XP_PST(NOP_MODE), S3C2410_ADCTSC) // YM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,Y方向测量模式 #define mode_y_axis() __raw_writel(0x0000009a, S3C2410_ADCTSC) // __raw_writel(0x00007ffa, S3C2410_ADCCON); -- A/D转换器预分频器使能,预分频值0xff,模拟输入通道SEL_MUX为XP,正常工作模式,使能读启动操作 // __raw_readl(S3C2410_ADCDAT0); -- 读取ADCDAT)的值 #define start_adc_x() do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \ __raw_readl(S3C2410_ADCDAT0); } while(0) // 怎么跟start_adc_x()配置一样?应该为0x00007fea? #define start_adc_y() do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \ __raw_readl(S3C2410_ADCDAT1); } while(0) // 禁止读启动操作,即READ_START位置0 #define disable_ts_adc() __raw_writel(__raw_readl(S3C2410_ADCCON)&0xfffffffd, S3C2410_ADCCON) static int adc_state = 0; static int x, y; /* touch screen coorinates */ #ifdef HOOK_FOR_DRAG #define RT_BT_EMU_TM ((HZ>>1)+(HZ>>2)) //0.75S //static u16 ts_r_x[5]; //static u16 ts_r_y[5]; //static u16 ts_r_idx; //static u16 ts_r_beg; static u32 dn_start; #endif static void tsEvent_raw(void) { DPRINTK("@@@@@@@@ tvEvent_raw() @@@@@@@@@\n"); if (tsdev.penStatus == PEN_DOWN) { //u16 i, j; #ifdef HOOK_FOR_DRAG ts_timer.expires = jiffies + TS_TIMER_DELAY; add_timer(&ts_timer); #endif BUF_HEAD.x = x; BUF_HEAD.y = y; #ifdef HOOK_FOR_DRAG BUF_HEAD.pressure = ((jiffies - dn_start) >= RT_BT_EMU_TM) ? PEN_FLEETING : PEN_DOWN; #else BUF_HEAD.pressure = PEN_DOWN; #endif }/* if (tsdev.penStatus == PEN_DOWN) */ else { #ifdef HOOK_FOR_DRAG del_timer(&ts_timer); #endif BUF_HEAD.x = x; BUF_HEAD.y = y; BUF_HEAD.pressure = PEN_UP; } tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF); DPRINTK("@@@@@@@@ wake_up_interruptible() in tvEvent_raw() @@@@@@@@@\n"); wake_up_interruptible(&(tsdev.wq)); #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) { printk("@@@@@ ts_ret.x: %hd, ts_ret.y: %hd @@@@@@@\n", ts_ret.x, ts_ret.y); 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); } #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(); } static inline void s3c2410_get_XY(void) { if (adc_state == 0) { adc_state = 1; disable_ts_adc(); y = __raw_readl(S3C2410_ADCDAT1) & 0x3ff; //x:f04 y:f0e dh by pht. mode_y_axis(); start_adc_y(); } else if (adc_state == 1) { adc_state = 0; disable_ts_adc(); x = __raw_readl(S3C2410_ADCDAT0) & 0x3ff; //y:f04 x:f0e dh by pht. printk("@@@@@@ PEN DOWN: x: %d, y: %d @@@@@@\n", x, y); wait_up_int(); tsdev.penStatus = PEN_DOWN; tsEvent(); } } static irqreturn_t s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg) { DPRINTK("@@@@@@@@ s3c2410_isr_adc() @@@@@@@@\n"); spin_lock_irq(&(tsdev.lock)); if (tsdev.penStatus == PEN_UP) { DPRINTK("@@@@@@ s3c2410_isr_adc 1 @@@@@@\n"); s3c2410_get_XY(); } #ifdef HOOK_FOR_DRAG else { DPRINTK("@@@@@@ s3c2410_isr_adc 2 @@@@@@\n"); s3c2410_get_XY(); } #endif spin_unlock_irq(&(tsdev.lock)); return IRQ_HANDLED; } static irqreturn_t s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg) { DPRINTK("@@@@@@@@ s3c2410_isr_tc() @@@@@@@@\n"); spin_lock_irq(&(tsdev.lock)); if (tsdev.penStatus == PEN_UP) { DPRINTK("@@@@@@@@ s3c2410_isr_tc 1 @@@@@@@@\n"); #ifdef HOOK_FOR_DRAG dn_start = jiffies; // add by gzliu #endif start_ts_adc(); } else { tsdev.penStatus = PEN_UP; DPRINTK("@@@@@@@@ s3c2410_isr_tc 2 @@@@@@@@\n"); printk("@@@@@@@ PEN UP: x: %d, y: %d @@@@@@@\n", x, y); wait_down_int(); tsEvent(); } spin_unlock_irq(&(tsdev.lock)); return IRQ_HANDLED; } #ifdef HOOK_FOR_DRAG static void ts_timer_handler(unsigned long data) { spin_lock_irq(&(tsdev.lock)); if (tsdev.penStatus == PEN_DOWN) { start_ts_adc(); } spin_unlock_irq(&(tsdev.lock)); } #endif static int s3c2410_ts_open(struct inode *inode, struct file *filp) { 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)); //MOD_INC_USE_COUNT; return 0; } static int s3c2410_ts_release(struct inode *inode, struct file *filp) { #ifdef HOOK_FOR_DRAG del_timer(&ts_timer); #endif //MOD_DEC_USE_COUNT; return 0; } static struct file_operations s3c2410_fops = { owner: THIS_MODULE, open: s3c2410_ts_open, read: s3c2410_ts_read, release: s3c2410_ts_release, #ifdef USE_ASYNC fasync: s3c2410_ts_fasync, #endif poll: s3c2410_ts_poll, }; void tsEvent_dummy(void) {} #ifdef CONFIG_PM static int s3c2410_ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) { switch (req) { case PM_SUSPEND: tsEvent = tsEvent_dummy; break; case PM_RESUME: tsEvent = tsEvent_raw; wait_down_int(); break; } return 0; } #endif static struct clk *adc_clock; static int __init s3c2410ts_probe(struct device *dev) { int ret; tsEvent = tsEvent_dummy; DPRINTK("@@@@@@@@@@ s3c2410ts_probe @@@@@@@@@@\n"); ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops); if (ret < 0) { printk(DEVICE_NAME " can't get major number\n"); return ret; } tsMajor = ret; adc_clock = clk_get(NULL, "adc"); if (!adc_clock) { printk(KERN_ERR "failed to get adc clock source\n"); return -ENOENT; } clk_use(adc_clock); clk_enable(adc_clock); base_addr = ioremap(S3C2410_PA_ADC, 0x20); __raw_writel(WAIT4INT(0), S3C2410_ADCTSC); __raw_writel(30000, S3C2410_ADCDLY); // 30000--20000 ret = request_irq(IRQ_ADC, s3c2410_isr_adc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_adc); if (ret) goto adc_failed; ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_tc); if (ret) goto tc_failed; /* Wait for touch screen interrupts */ wait_down_int(); #ifdef CONFIG_DEVFS_FS devfs_mk_dir("touchscreen"); devfs_mk_cdev(MKDEV(tsMajor, TSRAW_MINOR), S_IFCHR|S_IRUGO|S_IWUSR, "touchscreen/%s", "0raw"); #endif #ifdef CONFIG_PM tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT, s3c2410_ts_pm_callback); #endif return 0; tc_failed: { printk(KERN_ERR "tc failed!!!!!!!!!!!!!\n"); free_irq(IRQ_ADC, s3c2410_isr_adc); } adc_failed: { printk(KERN_ERR "adc failed!!!!!!!!!!!!!\n"); return ret; } } static struct device_driver s3c2410ts_driver = { .name = DEVICE_NAME, .bus = &platform_bus_type, .probe = s3c2410ts_probe, #ifdef CONFIG_PM .suspend = s3c2410ts_suspend, .resume = s3c2410ts_resume, #endif }; static int __init s3c2410ts_init(void) { int ret; printk("@@@@@@@@ s3c2410ts init() @@@@@@@\n"); ret = driver_register(&s3c2410ts_driver); if(ret) { printk("register %s driver failed, return code is %d\n", DEVICE_NAME, ret); } else { printk("@@@@@@@ register %s driver success, return code is %d @@@@@@@@@@\n", DEVICE_NAME, ret); } return ret; } static void __exit s3c2410ts_exit(void) { #ifdef CONFIG_DEVFS_FS devfs_remove("touchscreen/%d", 0); devfs_remove("touchscreen"); #endif unregister_chrdev(tsMajor, DEVICE_NAME); #ifdef CONFIG_PM pm_unregister(tsdev.pm_dev); #endif free_irq(IRQ_ADC, s3c2410_isr_adc); free_irq(IRQ_TC, s3c2410_isr_tc); driver_unregister(&s3c2410ts_driver); } module_init(s3c2410ts_init); module_exit(s3c2410ts_exit);