- 论坛徽章:
- 0
|
板子用的是friendlyarm的tiny6410, linux内核2.6.38,已经卸载了内核自带的ADC和触摸屏驱动。加载.ko模块后,用cat proc/devices 和 cat proc/interrupts ,中断也成功注册了,设备也成功注册了,但按下触摸屏就是不产生TC中断 ,就是不进入中断处理函数(我在TC中断处理函数开头用了printk观察的,始终没有打印)。如果用2.6.38自带的mini6410-ts.c编译成驱动模块加载,也不能工作。触摸屏确定是好的。求大神帮忙,谢谢!
以下是代码:
#include <linux/cdev.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/interrupt.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <mach/irqs.h>
#include <plat/regs-adc.h>
#include <asm/io.h>
#include <mach/hardware.h>
#define DEV_NAME "test_ts"
static unsigned int devno;
static struct class *myclass;
static struct clk *ts_clock;
static struct timer_list ts_timer;
static struct cdev ts_cdev;
#define HOOK_FOR_DRAG
#ifdef HOOK_FOR_DRAG
#define TS_TIMER_DELAY (HZ/100) //HZ:每秒timer interrupt次数 /* 10 ms */
#endif
#define UD_SEN_0 (0<< //Detect Stylus Down Interrupt Signal
#define UD_SEN_1 (1<< //Detect Stylus up Interrupt Signal
#define YM_SEN_1 (1<<7)
#define YP_SEN_1 (1<<6)
#define XM_SEN_0 (0<<5)
#define XP_SEN_1 (1<<4)
#define PULL_UP_0 (0<<3) //XP Pull-up Enable
#define AUTO_PST_0 (0<<2)
#define XY_PST_11 (3) //Waiting for Interrupt Mode
#define PRSCEN_1 (1<<14) //A/D converter prescaler enable
#define PRSCVL_50 ((49<<6)|0xc03f) //A/D converter prescaler value : 50
#define STDBM_0 (~(1<<2)) //Standby mode select: Normal operation mode
#define ENABLE_START_1 (1) //A/D conversion starts by enable
static void __iomem *base_addr;
#define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name))
#define ADCCON __ADCREG(S3C_ADCCON) // ADC control
#define ADCTSC __ADCREG(S3C_ADCTSC) // ADC touch screen control
#define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0
#define ADCDAT1 __ADCREG(S3C_ADCDAT1) // ADC conversion data 1
#define ADCUPDN __ADCREG(S3C_ADCUPDN)
//ADCTSC是指ADCTSC寄存器的内容
#define wait_down_int() ADCTSC = ( UD_SEN_0 | PULL_UP_0 | XP_SEN_1 | XM_SEN_0 | YP_SEN_1 | YM_SEN_1 | XY_PST_11 )
#define wait_up_int() ADCTSC = ( UD_SEN_1 | PULL_UP_0 | XP_SEN_1 | XM_SEN_0 | YP_SEN_1 | YM_SEN_1 | XY_PST_11 )
#define mode_x_axis() ADCTSC = ( ADCTSC & 0xff1 )
#define mode_y_axis() ADCTSC = ( ADCTSC & 0xff2 )
#define start_adc_x() ADCCON = (( ADCCON | PRSCEN_1 | ENABLE_START_1 )& STDBM_0 & PRSCVL_50 )
#define start_adc_y() ADCCON = (( ADCCON | PRSCEN_1 | ENABLE_START_1 )& STDBM_0 & PRSCVL_50 )
//#define start_adc_x() { ADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | ADC_NORMAL_MODE; ADCDAT0; }
//#define start_adc_y() { ADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | ADC_NORMAL_MODE; ADCDAT1; }
//#define mode_x_axis_n() { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | XP_PULL_UP_DIS | XP_PST(NOP_MODE); }
//#define start_adc_x() ADCTSC = (ADCTSC&(~0x3ul))|0x1 //ADCTSC是指ADCTSC寄存器的内容,将ADCTSC后两位置01
//#define disable_ts_adc()
#define PEN_UP 0 //弹起
#define PEN_DOWN 1 //按下
#define MAX_TS_BUF 8 //最大缓存数
typedef struct { //保存的转换数据结构
unsigned short pressure;
unsigned short x;
unsigned short y;
} TS_RET;
static unsigned int penStatus; //弹起0;按下1
static TS_RET buf[MAX_TS_BUF]; //缓存队列
static unsigned int head, tail;
static wait_queue_head_t wq;
static spinlock_t lock;
static int adc_state = 0; //adc_state=0指转换x ; adc_state=1指转换y ,(x/y分开转换模式)
static unsigned short x;
static unsigned short y;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//定义等待队列头
#define BUF_HEAD (buf[head])
#define BUF_TAIL (buf[tail])
#define INCBUF(x,mod) ((++(x)) & ((mod) - 1)) //x=0,1,2,3,4,5,6,7,0...
static void tsEvent(void)
{
if (penStatus == PEN_DOWN)
{ /* 保存按下时的坐标 */
BUF_HEAD.x = x;
BUF_HEAD.y = y;
BUF_HEAD.pressure = PEN_DOWN;
#ifdef HOOK_FOR_DRAG
ts_timer.expires = jiffies + TS_TIMER_DELAY; //expires:指定定时器到期的时间,到期时执行ts_timer_handler ,
// jiffies: 系统开机以来的timer interrupt次数,除以HZ就是时间
add_timer(&ts_timer); /* 对长时间按下键的处理 */
#endif
}
else
{
#ifdef HOOK_FOR_DRAG
del_timer(&ts_timer);
#endif
BUF_HEAD.x = 0;
BUF_HEAD.y = 0;
BUF_HEAD.pressure = PEN_UP; /* 保存弹起时的坐标 */ //弹起时不需转换
}
head = INCBUF(head, MAX_TS_BUF);
wake_up_interruptible(&wq); /* 唤醒进程 */
}
static inline void start_ts_adc(void)//AD转换函数
{
adc_state = 0;
mode_x_axis();
start_adc_x();
}
static inline void s3c6410_get_XY(void)
{
if (adc_state == 0) /* 转换x */
{
adc_state = 1; /* 下次转换y */
//disable_ts_adc();
x = (ADCDAT0 & 0x3ff); /* 获取x坐标 */
mode_y_axis();
start_adc_y(); /*启动y坐标转化*/
}
else if (adc_state == 1) /*转换y*/
{
adc_state = 0;
//disable_ts_adc();
y = (ADCDAT1 & 0x3ff); /* 获取y坐标 */
penStatus = PEN_DOWN; /* 改变屏状态为按下 */
printk("EN DOWN: x: %08d, y: %08d\n", x, y);
wait_up_int(); /* 等待弹起中断 */ //与程序是否阻塞无关!
tsEvent();
}
}
static irqreturn_t s3c6410_isr_adc(int irq, void *dev_id)
{
printk("adc irq1"
spin_lock_irq(&lock);
printk("adc irq2"
if (penStatus == PEN_UP) //如果是按下中断(按下之前是弹起的,penStatus=0)
s3c6410_get_XY();
#ifdef HOOK_FOR_DRAG
else
s3c6410_get_XY();
#endif
spin_unlock_irq(&lock);
return IRQ_RETVAL(IRQ_HANDLED);
}
static irqreturn_t s3c6410_isr_tc(int irq, void *dev_id)
{
printk("tc irq1"
spin_lock_irq(&lock);
printk("tc irq2"
if (penStatus == PEN_UP) //如果是按下中断(按下之前是弹起的,penStatus=0)
{
start_ts_adc(); /* 开始AD转化 */
}
else
{
penStatus = PEN_UP; /* 如果是弹起中断*/
printk("EN UP: x: %08d, y: %08d\n", x, y);
wait_down_int(); /*等待按下中断*/
tsEvent(); /* 调用后续处理函数 */
}
spin_unlock_irq(&lock);
return IRQ_RETVAL(IRQ_HANDLED);
}
#ifdef HOOK_FOR_DRAG
static void ts_timer_handler(unsigned long data)
{
spin_lock_irq(&lock);
if (penStatus == PEN_DOWN) {
start_ts_adc();
}
spin_unlock_irq(&lock);
}
#endif
static int s3c6410_ts_open(struct inode *inode, struct file *filp)
{
printk("open\n"
head = tail = 0;
penStatus = PEN_UP;//初始状态为弹起
#ifdef HOOK_FOR_DRAG
init_timer(&ts_timer);
ts_timer.function = ts_timer_handler;
#endif
//tsEvent = tsEvent_raw;
init_waitqueue_head(&wq);
//MOD_INC_USE_COUNT;
return 0;
}
static int s3c6410_ts_release(struct inode *inode, struct file *filp)
{
printk("release\n"
#ifdef HOOK_FOR_DRAG
del_timer(&ts_timer);
#endif
//MOD_DEC_USE_COUNT; //模块使用次数计数
return 0;
}
static int s3c6410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *offp)
{
printk("read\n"
TS_RET ts_ret;
unsigned long err;
retry:
if (head != tail)
{
int count;
spin_lock_irq(&lock);
ts_ret.x = BUF_TAIL.x;
ts_ret.y = BUF_TAIL.y;
ts_ret.pressure = BUF_TAIL.pressure;
tail = INCBUF(tail, MAX_TS_BUF);
spin_unlock_irq(&lock);
count = sizeof(ts_ret);
if (count)
err = copy_to_user(buffer, (char *)&ts_ret, count);
return err ? -EFAULT : count;
}
else
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&wq);
if (signal_pending(current))
return -ERESTARTSYS;
goto retry;
}
return sizeof(TS_RET);
}
static unsigned int s3c6410_ts_poll(struct file *filp, struct poll_table_struct *wait)
{
printk("poll\n"
poll_wait(filp, &wq, wait);
if(head != tail)
return (POLLIN | POLLRDNORM);
else
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = s3c6410_ts_open,
.release = s3c6410_ts_release,
.read = s3c6410_ts_read,
.poll = s3c6410_ts_poll,
};
static int __init s3c6410_ts_init(void)
{
int ret;
void __iomem *VIC1_INTENABLE;
VIC1_INTENABLE = ioremap(0x71300010, 4);
printk("%lx\n", (*(volatile unsigned long *)VIC1_INTENABLE) );
//unsigned int devno;
base_addr = ioremap(0x7E00B000, 4);
ts_clock = clk_get( NULL, "adc" );
printk("IS_ERR(ts_clock)= %ld\n", IS_ERR(ts_clock));
if (IS_ERR(ts_clock))
{
printk("%ld, failed to find watchdog clock source\n", IS_ERR(ts_clock));
//ret = PTR_ERR(ts_clock);
//goto err_clk;
}
ret = clk_enable(ts_clock);
printk("ret= %d\n", ret );
alloc_chrdev_region(&devno, 0, 1, DEV_NAME);//动态分配设备号
printk("%d\n",MAJOR(devno));
cdev_init(&ts_cdev, &dev_fops);
ts_cdev.owner = THIS_MODULE;
ret=cdev_add(&ts_cdev, devno, 1);
if(ret)
printk(KERN_NOTICE "Error adding cdev\n"
//set_gpio_ctrl(GPIO_YPON);
//set_gpio_ctrl(GPIO_YMON);
//set_gpio_ctrl(GPIO_XPON);
//set_gpio_ctrl(GPIO_XMON);
/* 注册中断 */
ret = request_irq(IRQ_ADC, s3c6410_isr_adc, IRQF_DISABLED|IRQF_SHARED, //IRQF_DISABLED禁止中断被中断
DEV_NAME, s3c6410_isr_adc);
printk("adc ret=%d\n",ret);
if (ret) goto adc_failed;
ret = request_irq(IRQ_TC, s3c6410_isr_tc, IRQF_DISABLED,
DEV_NAME, s3c6410_isr_tc);
printk("tc ret=%d\n",ret);
if (ret) goto tc_failed;
/* 等待触摸屏被按下的中断 */
wait_down_int();
//printk("ADCTSC=%lx\n", ADCTSC);
printk(DEV_NAME"\tinitialized\n"
myclass = class_create(THIS_MODULE, "char_dev");
device_create(myclass, NULL, devno, NULL, DEV_NAME); //struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
return 0;
tc_failed:
//printk("tc failed");
free_irq(IRQ_ADC, s3c6410_isr_adc);
adc_failed:
//printk("adc failed");
return ret;
}
static void __exit s3c6410_ts_exit(void)
{
device_destroy(myclass, devno);
class_destroy(myclass);
cdev_del(&ts_cdev);
free_irq(IRQ_ADC, s3c6410_isr_adc);
free_irq(IRQ_TC, s3c6410_isr_tc);
clk_disable(ts_clock);
}
module_init(s3c6410_ts_init);
module_exit(s3c6410_ts_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("QX");
|
|