mini2440触摸屏驱动----非input子系统实现方法

来源:互联网 发布:java开发虚假经历 编辑:程序博客网 时间:2024/06/06 06:44

触摸屏的驱动程序在不是使用input子系统的实现过程中,其实和普通的字符设备驱动没有太大的差别,只要按照触摸屏那几个步骤正常进行就可以。

①s3c2410_ts_init函数,这是整个程序的入口处。实现了各类初始化的作用。

/*设备初始化函数*/static int __init s3c2410_ts_init(void){int ret;tsEvent = tsEvent_dummy;/* 注册字符设备第一个参数为0表示自动分配*/ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);//普通的注册失败判断。if (ret < 0) {  printk(DEVICE_NAME " can't get major number\n");  return ret;}//tsMajor是一个全局变量,这里被赋设备注册的返回值tsMajor = ret;/* set gpio to XP, YM, YP and  YM *///操作相应的GPIO寄存器,这些函数是内核留下来的接口。set_gpio_ctrl(GPIO_YPON); set_gpio_ctrl(GPIO_YMON);set_gpio_ctrl(GPIO_XPON);set_gpio_ctrl(GPIO_XMON);/*注册中断分别注册ADC和TC中断。DEVICE_NAME在开始处有宏定义。*/ret = request_irq(IRQ_ADC_DONE, 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_down_int();//创建设备文件。#ifdef CONFIG_DEVFS_FSdevfs_ts_dir = devfs_mk_dir(NULL, "touchscreen", NULL);devfs_tsraw = devfs_register(devfs_ts_dir, "0raw", DEVFS_FL_DEFAULT,tsMajor, TSRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,&s3c2410_fops, NULL);#endifADCDLY = 0xFFFF;printk(DEVICE_NAME " initialized\n");return 0;//两个中断注册失败的跳转点。 tc_failed:free_irq(IRQ_ADC_DONE, s3c2410_isr_adc); adc_failed:return ret;}

在这个函数中出现了以前没有的条件编译,所以自己注意一下,不过这个条件编译的主要作用就是创建设备文件。同时还有两个中断注册失败的goto。为了自己看以后的程序不糊涂,先记下这句话://tsMajor是一个全局变量,这里被赋设备注册的返回值tsMajor = ret;

 

②s3c2410_ts_exit,这个函数是整个程序的退出函数,主要实现了设备的注销和中断的释放。

static void __exit s3c2410_ts_exit(void){#ifdef CONFIG_DEVFS_FSdevfs_unregister(devfs_tsraw);devfs_unregister(devfs_ts_dir);#endifunregister_chrdev(tsMajor, DEVICE_NAME);free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);free_irq(IRQ_TC, s3c2410_isr_tc);}


③一般分析字符设备驱动程序的时候都是先看init函数,然后再去找file_operation。但是触摸屏的驱动程序的实现肯定有会有中断,所以我们先来看一下中断函数。

先看第一个中断函数(在init函数中已经注册完毕)

/* 当按键按下时首先产生的中断 */static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg){//利用自旋锁给中断上锁。spin_lock_irq(&(tsdev.lock));//这里PEN_UP被宏定义为0,penStatus是一个结构体成员。if (tsdev.penStatus == PEN_UP) /*如果是按下中断*/{  start_ts_adc(); /* 开始AD转化 */} else {  tsdev.penStatus = PEN_UP; /* 如果是弹起中断*/  DPRINTK("PEN UP: x: %08d, y: %08d\n", x, y);  wait_down_int(); /*等待按下中断*/  tsEvent(); /* 调用后续处理函数 */}spin_unlock_irq(&(tsdev.lock));}

再说这个中断函数之前,首先要说一下触摸品主要的工作流程:

触摸屏的工作流程
①选择X/Y的获取模式。
②设置触摸屏等待中断的状态。
③如果中断发生启动相应的数模转换。
④当数模转换之后,可以获取X/Y坐标值,返回到等待中断的状态(②之后③之前)。

同时还要说一下触摸屏的两个中断:

TC中断:手按下拿起的时候
ADC中断:发生在第四步。

上面的中断处理函数其实就是TC中断,从名字也可以看得出来,也就是触摸屏发生的第一个中断。

当中断发生的时候首先是自旋锁上锁。然后给出判定并分配了两种情况,假如确实是按下了,那么就开始进行AD转换,AD转换的函数在另一个函数中实现,这里只是调用。如果是弹起中断,那么就继续等待,并调用后续函数(这里的后续函数一定要仔细的看)。

上面的TC中断函数中一共调用了两个函数,分别是start_ts_adc和tsEvent函数。下面分别介绍这两个函数。

start_ts_adc函数:

//通过响应的寄存器的设置来启动AD转换。//mode_x_axis,start_adc_x都是宏定义的函数。static inline void start_ts_adc(void){ adc_state = 0; mode_x_axis(); start_adc_x();}

这个函数主要是通过操作寄存器来实现的,具体的定义在整个程序开始的宏定义中有表现。

tsEvent函数:

static void tsEvent_raw(void){if (tsdev.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;add_timer(&ts_timer); /* 对长时间按下键的处理 这个函数的具体实现在本函数中实现。*/#endif} else {#ifdef HOOK_FOR_DRAG del_timer(&ts_timer);#endifBUF_HEAD.x = 0;BUF_HEAD.y = 0;BUF_HEAD.pressure = PEN_UP; /* 保存弹起时的坐标 */}tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);//这里的唤醒进程和read函数中的sleep on对应。wake_up_interruptible(&(tsdev.wq)); /* 唤醒进程 */}


在等待按下中断函数后再调用后续处理函数,这里是一个循环的调用。在后续处理函数要注意:

#ifdef HOOK_FOR_DRAG
/*当笔在触摸屏上长期滑动的时候,如果不进行特殊处理不会产生点的轨迹。*/
  ts_timer.expires = jiffies + TS_TIMER_DELAY;
  add_timer(&ts_timer);

      /*
        对长时间按下键的处理
        这个函数的具体实现在本函数中实现。
       */
#endif

这个函数是针对长时间按键的情况,这里ts_timer实现了检测频率的体现,同时,ts_timer中实现了如下函数:

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));}

这样长时间按键的情况就不是检测连个中断了,而且检测的频率还可以自己进行设定。

④当TC中断函数执行完成以后自然而然的根据IRQ中断号就要执行另一个中断ADC中断了。

static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg){spin_lock_irq(&(tsdev.lock));if (tsdev.penStatus == PEN_UP)  s3c2410_get_XY();#ifdef HOOK_FOR_DRAGelse  s3c2410_get_XY();#endifspin_unlock_irq(&(tsdev.lock));}

这一部分是ADC实现的代码。其中这个函数主要调用了 s3c2410_get_XY这个函数,包括判定之后的执行也都是在s3c2410_get_XY这个函数再进行进一步判定之后进行的。

下面列出s3c2410_get_XY这个函数的主要代码:

static inline void s3c2410_get_XY(void){//adc_state这个变量的作用是区分现在到底在获取哪一个坐标。if (adc_state == 0) { /* 转换x */adc_state = 1;disable_ts_adc();y = (ADCDAT0 & 0x3ff); /* 获取x坐标 */mode_y_axis(); start_adc_y(); /*启动y坐标转化*/} else if (adc_state == 1) {  /*转换y*/adc_state = 0;disable_ts_adc();x = (ADCDAT1 & 0x3ff); /* 获取y坐标 */tsdev.penStatus = PEN_DOWN; /* 改变屏状态 */DPRINTK("PEN DOWN: x: %08d, y: %08d\n", x, y);wait_up_int();   /* 等待弹起中断 */tsEvent();}}

在上述的几个中断程序中涉及到了部分流程控制的循环调用,所以大家务必仔细阅读。

⑤中断讲解完毕以后开始说一下file_operations。

多么的亲切!

static struct file_operations s3c2410_fops = {
 owner: THIS_MODULE,
 open: s3c2410_ts_open,
 read: s3c2410_ts_read, 
 release: s3c2410_ts_release,
 poll: s3c2410_ts_poll,
};

说到了file_operations了,那么就把代码分别粘贴出来了ha~

s3c2410_ts_open:

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;#endiftsEvent = tsEvent_raw;init_waitqueue_head(&(tsdev.wq));MOD_INC_USE_COUNT;return 0;}

说到这里还有一个问题没有弄懂,那就是tsdev.head = tsdev.tail = 0;不懂为什么头和尾都要置零。其他的部分也就不做过多的解释了。
s3c2410_ts_read函数:

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) 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);}

注意一下这里://这个判断的作用是:判断是否是信号把它唤醒了if (signal_pending(current))。

release函数:

static int s3c2410_ts_release(struct inode *inode, struct file *filp){#ifdef HOOK_FOR_DRAGdel_timer(&ts_timer);#endifMOD_DEC_USE_COUNT;return 0;}

大体部分也就上面这些,我是在看过了input子系统实现了触摸屏驱动之后写的这个,突然感觉还是input子系统实现起来比这个简单了很多。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车里玻璃水冻了怎么办 做现货亏了60万怎么办 宿舍太吵晚上睡不着觉怎么办 脚扎了钉子肿了怎么办 龙血树叶子下垂怎么办 龙血树叶子卷曲怎么办 3岁宝宝长期便秘怎么办 4岁小儿便秘严重怎么办 3岁宝宝便秘严重怎么办 3岁宝宝一直便秘怎么办 11个月宝宝便秘怎么办 2个月的宝宝便秘怎么办 宝宝便秘拉不下来怎么办 5一6岁儿童便秘怎么办 3个月宝宝便秘怎么办 8个月宝宝便秘怎么办 孕5个月咳嗽厉害怎么办 孕8个月咳嗽厉害怎么办 拆石膏后关节僵硬怎么办 宝宝的小腿不直怎么办 鸡咳嗽有痰呼噜怎么办 风热感冒怎么办小窍门 吃完虾喝了牛奶怎么办 三文鱼头汤腥怎么办 晚上咳嗽厉害怎么办睡不着觉 刚怀孕发烧39度怎么办 刚怀孕发烧38度怎么办 怀孕10天发烧了怎么办 怀孕2个月发烧了怎么办 lol误封3年怎么办 心悦会员到期了怎么办 心悦游戏家到期怎么办 无间鬼后运气背怎么办 趣店被骗提现了怎么办 微转奇迹闪退怎么办 奇迹暖暖ios闪退怎么办 奇迹mu任务没做怎么办 外地人在北京上社保怎么办 医社保中间断了怎么办 社保断了2年怎么办 孩子的社保断了怎么办