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子系统实现起来比这个简单了很多。
- mini2440触摸屏驱动----非input子系统实现方法
- mini2440的触摸屏驱动----使用input子系统实现
- 输入子系统实现的mini2440按键驱动
- 触摸屏驱动之先修知识——Input子系统
- 实例:触摸屏驱动-2.用input子系统报告事件
- mini2440触摸屏驱动详解
- Mini2440 触摸屏驱动分析
- mini2440触摸屏驱动移植
- Mini2440 触摸屏驱动分析
- mini2440触摸屏驱动详解
- mini2440之触摸屏驱动
- 基于mini2440触摸屏驱动
- mini2440触摸屏驱动分析
- linux input子系统键盘驱动实现
- linux input子系统键盘驱动实现
- Microwindows 及其 触摸屏驱动 在eCos MINI2440 上的实现
- input子系统七之触摸屏驱动开发实例1(ADC驱动实例)
- 【笔记】mini2440触摸屏驱动移植
- 如何jax异步实现附件上传工作
- 关于SPI的小问题
- VMware9虚拟机安装MAC OS X Mountain Lion 10.8.2详细图文教程
- 关于Matlab调用C函数的问题
- c# 生成静态页面
- mini2440触摸屏驱动----非input子系统实现方法
- 一个串口接收数据的状态机
- 两个JSP页面,从①页面经过STRUTS跳转到另一个②JSP页面
- 等待了三天,终于可以发博客啦
- Eclipse中为SVN设置快捷键
- 遗传算法入门
- 设置TextBox控件为数字输入
- SQL 查出多条数据 用逗号隔开 合并某一列的 标量函数
- 在WPF中使用WindowProc处理消息