armlinux学习笔记--触摸屏驱动程序分析_第1页
armlinux学习笔记--触摸屏驱动程序分析_第2页
armlinux学习笔记--触摸屏驱动程序分析_第3页
armlinux学习笔记--触摸屏驱动程序分析_第4页
armlinux学习笔记--触摸屏驱动程序分析_第5页
免费预览已结束,剩余20页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、armlinux 学习笔记触摸屏驱动程序分析*/*2007.6.26*Linux 下的触摸屏驱动程序主要都在/kernel/drivers/char/s3c2410-ts.c 文件中。触摸屏的file_operations 结构定义如下:staticstructfile_operationss3c2410_fops=owner:THIS_MODULE,open:s3c2410_ts_open,read:s3c2410_ts_read,release:s3c2410_ts_release,#ifdefUSE_ASYNCfasync:s3c2410_ts_fasync,#endifpoll:s3c

2、2410_ts_poll,;在触摸屏设备驱动程序中,全局变量 structTS_DEVtsdev 是很重要的,用来保存触摸屏的相关参数、等待处理的消息队列、当前采样数据、上一次采样数据等信息,数据结构 structTS_DEV 的定义如下:typedefstructunsignedintpenStatus;/*PEN_UP,PEN_DOWN,PEN_SAMPLE*/TS_RETbufMAX_TS_BUF;/*protectagainstoverrun(环形缓冲区)*/unsignedinthead,tail;/*headandtailforqueuedevents(环形缓冲区的头尾)*/wai

3、t_queue_head_twq;/*等待队列数据结构 spinlock_tlock;/*自旋锁#ifdefUSE_ASYNCstructfasync_struct*aq;#endif#ifdefCONFIG_PMstructpm_dev*pm_dev;#endifTS_DEV;staticTS_DEVtsdev;在/kernel/include/asm-arm/linuette_ioctl.h 文件中:typedefstructunsignedshortpressure;/*压力,这里可定义为笔按下,笔抬起,笔拖曳unsignedshortx;/*横坐标的采样值unsignedshorty;

4、/*纵坐标的采样值unsignedshortpad;/*填充位TS_RET;在/kernel/include/linux/wait.h 文件中:struct_wait_queue_headwq_lock_tlock;structlist_headtask_list;#ifWAITQUEUE_DEBUGlong_magic;long_creator;#endif;typedefstruct_wait_queue_headwait_queue_head_t;TS_RET 结构体中的信息就是驱动程序提供给上层应用程序使用的信息,用来存储触摸屏的返回值。上层应用程序通过读接口,从底层驱动中读取信息,并

5、根据得到的值进行其他方面的操作。TS_DEV 结构用于记录触摸屏运行的各种状态, PenStatu 匏括 PEN_UP、PEN_DOWN 和PEN_FLEETING。bufMAX_TS_BUF是用来存放数据信息的事件队列,head、tail 分别指向事件队列的头和尾。 程序中的笔事件队列是一个环形结构, 当有事件加入时,队列头加一,当有事件被取走时, 队列尾加一, 当头尾位置指针一致时读取笔事件的信息,进程会被安排进入睡眠。wq 等待队列,包含一个锁变量和一个正在睡眠进程链表。当有好几个进程都在等待某件事时,Linux 会把这些进程记录到这个等待队列。它的作用是当没有笔触事件发生时,阻塞上层的

6、读操作,直到有笔触事件发生。lock 使用自旋锁,自旋锁是基于共享变量来工作的,函数可以通过给某个变量设置一个特殊值来获得锁。而其他需要锁的函数则会循环查询锁是否可用。 MAX_TS_BUF 的值为 16,即在没有被读取之前,系统缓冲区中最多可以存放 16 个笔触数据信息。 (关于自旋锁的作用和概念可以参考一篇 Linux内核的同步机制文章的相关章节。)模块初始化函数是调用 s3c2410_ts_init 函数来实现的,主要完成触摸屏设备的内核模块加载、初始化系统 I/O、中断注册、设备注册,为设备文件系统创建入口等标准的字符设备初始化工作。staticint_inits3c2410_ts_i

7、nit(void)ret=register_chrdev(0,DEVICE_NAME,&s3c2410_fops);tsMajor=ret;这里首先对字符设备进行注册,将触摸屏的 file_operations 结构中的函数接口传入内核,注册成功后获得系统自动分配的主设备号。set_gpio_ctrl(GPIO_YPON);set_gpio_ctrl(GPIO_YMON);set_gpio_ctrl(GPIO_XPON);set_gpio_ctrl(GPIO_XMON);在/kernel/include/asm-arm/arch-s3c2410/smdk.h 文件中:# defineG

8、PIO_YPON(GPIO_MODE_nYPON|GPIO_PULLUP_DIS|GPIO_G15)# defineGPIO_YMON(GPIO_MODE_YMON|GPIO_PULLUP_EN|GPIO_G14)# defineGPIO_XPON(GPIO_MODE_nXPON|GPIO_PULLUP_DIS|GPIO_G13)# defineGPIO_XMON(GPIO_MODE_XMON|GPIO_PULLUP_EN|GPIO_G12)GPIO的 PortG 端口有 4 个管脚对应触摸屏的控制接口,分别是:GPG15-nYPONY+控制信号GPG14-YMONY-控制信号GPG13-nX

9、PONX+控制信号GPG12-XMONX-控制信号需要通过配置 GPGCON 寄存器来设定该端口管脚的输出模式, 对应位如下:31:3029:2827:2625:24GPG15GPG14GPG13GPG12.参考 S3c2410 芯片 datasheet 的 I/O 口章节,都要设为 11(二进制)。ADCDLY=30000;配置 ADCDLY 寄存器,对自动转换模式来说是设定 ADC 开始转换时的延时时间,以及对 X轴和 Y 轴转换的时间间隔, 对正常模式来说仅设定对 X 轴和 Y 轴转换的时间间隔。注意该值不能为 0。在/kernel/arch/arm/kernel/irq.c 文件中:/

10、* request_irq-allocateaninterruptline* irq:Interruptlinetoallocate* handler:FunctiontobecalledwhentheIRQoccurs* irqflags:Interrupttypeflags* devname:Anasciinamefortheclaimingdevice* dev_id:Acookiepassedbacktothehandlerfunction* Thiscallallocatesinterruptresourcesandenablesthe* interruptlineandIRQhan

11、dling.Fromthepointthis* callismadeyourhandlerfunctionmaybeinvoked.Since* yourhandlerfunctionmustclearanyinterrupttheboard* raises,youmusttakecarebothtoinitialiseyourhardware* andtosetuptheinterrupthandlerintherightorder.* Dev_idmustbegloballyunique.Normallytheaddressofthe* devicedatastructureisuseda

12、sthecookie.Sincethehandler* receivesthisvalueitmakessensetouseit.* IfyourinterruptissharedyoumustpassanonNULLdev_id* asthisisrequiredwhenfreeingtheinterrupt.* Flags:* SA_SHIRQInterruptisshared* SA_INTERRUPTDisablelocalinterruptswhileprocessing* SA_SAMPLE_RANDOMTheinterruptcanbeusedforentropy*/intreq

13、uest_irq(unsignedintirq,void(*handler)(int,void*,structpt_regs*),unsignedlongirq_flags,constchar*devname,void*dev_id)其中 handler 函数指针的具体参数为:void(*handler)(intirq,void*dev_id,structpt_regs*regs)函数 request_irq 是 Linux 系统中驱动程序注册中断的方法。irq 为所要申请的硬件中断号,handler 为系统所注册的中断处理子程序,irq_flags 为申请时的选项,devname 为指向设备

14、名称的字符指针,dev_id 为申请时告诉系统的设备标识。若中断申请成功则返回 0,失败则返回负值。ret=request_irq(IRQ_ADC_DONE,s3c2410_isr_adc,SA_INTERRUPT,DEVICE_NAME,s3c2410_isr_adc);调用该函数来进行 A/D 转换的中断注册,所要申请的硬件中断号为IRQ_ADC_DONE(62);系统所注册的中断处理子程序为 s3c2410_isr_adc 函数;申请中断选项为 SA_INTERRUPT,表示中断处理程序是快速处理程序,即快速处理程序运行时,所有中断都被屏蔽;设备名称定义为 DEVICE_NAME,即s3

15、c2410-ts;而设备标识仍然用中断处理子程序代替。ret=request_irq(IRQ_TC,s3c2410_isr_tc,SA_INTERRUPT,DEVICE_NAME,s3c2410_isr_tc);接着继续调用该函数来进行触摸屏触摸的中断注册, 所要申请的硬件中断号为 IRQ_TC(61);系统所注册的中断处理子程序为 s3c2410_isr_tc 函数;申请中断选项为SA_INTERRUPT,表示中断处理程序是快速处理程序,即快速处理程序运行时,所有中断都被屏蔽;设备名称定义为 DEVICE_NAME,即s3c2410-ts;而设备标识仍然用中断处理子程序代替。/*Waitfo

16、rtouchscreeninterrupts*/wait_down_int();调用该宏函数来设置触摸屏为等待中断模式【笔按下产生中断】,具体定义如下:#definewait_down_int()ADCTSC=DOWN_INT|XP_PULL_UP_EN|XP_AIN|XM_HIZ|YP_AIN|YM_GND|XP_PST(WAIT_INT_MODE);用该宏函数来设置 ADC 触摸屏控制寄存器,参考 S3C2410 芯片datasheet 中关于触摸屏的章节,具体设置参数如下:DOWN_INT=18*0 该位保留且应该设为 01 笔按下或笔抬起中断信号控制位,设为 0表示笔按下产生中断信号】

17、XP_PULL_UP_EN=13*0 上拉开关使能, 设为 0表示 XP 引脚上拉使能选择nXPON 引 脚 输 出 值 , 设 为 1 表 示nXPON引脚输出 1,则 XP 引脚选择XMON 引脚输出值, 设为 0 表示 XMON引脚输出 0,则 XM 引选择nYPON 引 脚 输 出 值 , 设 为 1 表 示nYPON引脚输出 1,则 YP 引脚选择 YMON 引脚输出值,设为 1 表示 YMON 引脚输出 1,则 YM 引X 坐标 Y坐标手动测量设置,设为 3表示等待中断模式#ifdefCONFIG_DEVFS_FSdevfs_ts_dir=devfs_mk_dir(NULL,tou

18、chscreen,NULL);devfs_tsraw=devfs_register(devfs_ts_dir,0raw,DEVFS_FL_DEFAULT,tsMajor,TSRAW_MINOR,S_IFCHR|S_IRUSR|S_IWUSR,&s3c2410_fops,NULL);#endifXP_AIN=14*1 连接 AIN7引脚XM_HIZ=15*0 脚为高阻态YP_AIN=16*1 连接 AIN5引脚YM_GND=17*1 脚为接地XP_PST(WAIT_INT_MODE);=3以上这两个函数在我总结的一篇 LCD 驱动程序分析 中有较详细的介绍。这里调用了 devfs_mk_

19、dir 函数,在设备文件系统中创建了一个名为touchscreen 的目录,并返回一个带有目录结构的数据结构变量 devfs_ts_dir。将该变量作为下一步 devfs_register函数的参数,该参数在调用设备文件系统注册清除函数 devfs_unregister 时也要作为参数传入。调用 devfs_register 函数后,会在刚才创建的 touchscreen 目录下再创建一个名为 0raw 的设备文件节点。 该函数的参数中, DEVFS_FL_DEFAULT 为该函数的标志选项,tsMajor 为注册字符设备时系统自动分配的主设备号,TSRAW_MINOR(1)为次设备号,S_I

20、FCHR|S_IRUSR|S_IWUSR 为默认的文件模式, &s3c2410_fops 为传入内核的触摸屏 file_operations 结构中的函数接口,私有数据指针为空。返回一个devfs_handle_t 数据结构的变量 devfs_tsraw,这会在调用设备文件系统注册清除函数 devfs_unregister 时作为参数传入。模块的退出函数为s3c2410_ts_exit,该函数的工作就是清除已注册的字符设备,中断以及设备文件系统。#ifdefCONFIG_DEVFS_FSdevfs_unregister(devfs_tsraw);devfs_unregister(dev

21、fs_ts_dir);#endif这里首先清除原先后一步创建设备文件节点 0raw 的结构变量devfs_tsraw,然后再清除创建 touchscreen 目录的结构变量 devfs_ts_dir。unregister_chrdev(tsMajor,DEVICE_NAME);接下来疝除字符设备的注册信息。在/kernel/arch/arm/kernel/irq.c 文件中:/* free_irq-freeaninterrupt* irq:Interruptlinetofree* dev_id:Deviceidentitytofree* Removeaninterrupthandler.The

22、handlerisremovedandifthe* interruptlineisnolongerinusebyanydriveritisdisabled.* OnasharedIRQthecallermustensuretheinterruptisdisabled* onthecarditdrivesbeforecallingthisfunction.* Thisfunctionmaybecalledfrominterruptcontext.*/voidfree_irq(unsignedintirq,void*dev_id)函数 free_irq 与函数 request_irq 相对应,通常

23、在模块被卸载时调用,负责注销一个已经申请的中断。free_irq(IRQ_ADC_DONE,s3c2410_isr_adc);free_irq(IRQ_TC,s3c2410_isr_tc);最后依次注销 A/D 转换和定时器这两个已经申请的中断。接下来看一下 A/D 转换的中断处理函数:staticvoids3c2410_isr_adc(intirq,void*dev_id,structpt_regs*reg)其中参数 irq 为中断号,dev_id 为申请中断时告诉系统的设备标识,regs为中断发生时寄存器内容。该函数在中断产生时由系统来调用,调用时以上参数已经由系统传入。在/kernel/

24、include/linux/spinlock.h 文件中:/*# Thesearethegenericversionsofthespinlocksandread-write# locks.# /# definespin_lock_irq(lock)dolocal_irq_disable();spin_lock(lock);while(0)# definespin_unlock_irq(lock)dospin_unlock(lock);local_irq_enable();while(0)# defineDEBUG_SPINLOCKS0/*0=nodebugging,1=maintainlock

25、state,2=fulldebug# /# if(DEBUG_SPINLOCKS1)typedefstructspinlock_t;#defineSPIN_LOCK_UNLOCKED(spinlock_t)# definespin_lock_init(lock)dowhile(0)#definespin_lock(lock)(void)(lock)/*Notunusedvariable.*/# definespin_unlock_wait(lock)dowhile(0)# definespin_unlock(lock)dowhile(0)可见上面这四个宏函数都是空函数,这样白话 spin_lo

26、ck_irq(lock)和spin_unlock_irq(lock)这两个宏函数就相当于分别只调用了 local_irq_disable();和 local_irq_enable();两个宏函数。关于自旋锁的作用和概念可以参考一篇Linux 内核的同步机制文章的相关章节。在/kernel/include/asm-arm/system.h 文件中:# definelocal_irq_disable()_cli()# definelocal_irq_enable()_sti()在/kernel/include/asm-arm/proc-armo/system.h 文件中:/* EnableIRQs

27、* /*define_sti()dounsignedlongtemp;_asmvolatile_(mov%0,pcstinbic%0,%0,#0 x08000000nteqp%0,#0n:=r(temp):memory);while(0)/*DisableIRQs*/#define_cli()dounsignedlongtemp;_asmvolatile_(mov%0,pcclinorr%0,%0,#0 x08000000nteqp%0,#0n:=r(temp):memory);while(0)最后用 ARM 汇编指令实现了对 IRQ 的使能和禁止。spin_lock_irq(&(ts

28、dev.lock);这样调用spin_lock_irq宏函数, 实际上只是做了local_irq_disable();一步,就是禁止 IRQ 中断。if(tsdev.penStatus=PEN_UP)s3c2410_get_XY();然 后 根 据 变 量 tsdev.penStatus 所 处 的 状 态 , 若 为 笔 抬 起 则 调 用s3c2410_get_XY 函数来取得 A/D 转换得到的坐标值,该函数会在后面说明。#ifdefHOOK_FOR_DRAGelses3c2410_get_XY();#endif这里表示如果定义了笔拖曳,且在笔没有抬起的情况下,继续调用s3c2410_g

29、et_XY 函数来得到最新的坐标值。spin_unlock_irq(&(tsdev.lock);最后调用spin_unlock_irq宏函数, 相当于只做了local_irq_enable();一步,来重新使能 IRQ 中断。最后退出这个中断服务子程序。继续来看一下另一个中断处理函数,即触摸屏触摸中断处理函数:staticvoids3c2410_isr_tc(intirq,void*dev_id,structpt_regs*reg)该函数的参数和上面 A/D 转换中断处理函数的定义一样,不再累赘。spin_lock_irq(&(tsdev.lock);也同上面的意思一样,首先禁

30、止 IRQ 中断。if(tsdev.penStatus=PEN_UP)start_ts_adc();接着根据变量 tsdevpenStatus 的状态值判断是否进行 A/D 转换。若笔抬起,则调用函数start_ts_adc 来进行 A/D 转换,该函数会在后面说明。elsetsdev.penStatus=PEN_UP;DPRINTK(PENUP:x:%08d,y:%08dn”,x,y);wait_down_int();tsEvent();如果变量 tsdev.penStatus 的状态值不是笔抬起,则先将该变量状态设为笔抬起,然后调用宏函数 wait_down_int()。该宏函数已在前面说

31、明,用来设置触摸屏为等待中断模式。最后调用 tsEvent 函数指针所指的函数,在模块初始化函数 s3c2410_ts_init 中,tsEvent 指向的是一个空函数 tsEvent_dummy,而在打开设备函数 s3c2410_ts_open 中,tsEvent 会指向 tsEvent_raw 函数,该函数负责填充触摸屏缓冲区,并唤醒等待的进程。该函数也会在后面加以说明。spin_unlock_irq(&(tsdev.lock);中断处理函数的最后一步都一样,重新使能 IRQ 中断。退出中断服务子程序。下面先来看启动 A/D 转换的函数:staticinlinevoidstart_

32、ts_adc(void)adc_state=0;mode_x_axis();start_adc_x();简简单单的 3 步。第一步,对 A/D 转换的状态变量清零。第二步,调用 mode_x_axis 宏函数,具体定义如下:#definemode_x_axis()ADCTSC=XP_EXTVLT|XM_GND|YP_AIN|YM_HIZ|XP_PULL_UP_DIS|XP_PST(X_AXIS_MODE);*/*2007.6.27*该宏函数用来设置 ADC 触摸屏控制寄存器为测量 X 坐标模式,参考S3c2410 芯片 datasheet 中关于触摸屏的章节,具体设置参数如下:XP_EXTVL

33、T=14*0 选择 nXPON 引脚输出值, 设为 0 表示 nXPON 引脚输出 0,贝 UXP引脚为接外部电压XM_GND=15*1 选择 XMON 引脚输出值,设为 1 表示 XMON 引脚输出 1,则 XM 引脚为接地YP_AIN=16*1 选择 nYPON 引脚输出值,设为 1 表示 nYPON 引脚输出 1,则 YP 引脚连接 AIN5引脚YM_HIZ=17*0 选择 YMON 引脚输出值,设为 0 表示 YMON 引脚输出 0,则 YM 引脚为高阻态XP_PULL_UP_DIS=13*1 上拉开关使能,设为 1 表示 XP 引脚上拉禁止XP_PST(X_AXIS_MODE);=1

34、X 坐标丫坐标手动测量设置,设为 1 表示 X 坐标测量模式第三步,调用 start_adc_x 宏函数,具体定义如下:#definestart_adc_x()ADCCON=PRESCALE_EN|PRSCVL(49)|ADC_INPUT(ADC_IN5)|ADC_START_BY_RD_EN|ADC_NORMAL_MODE;ADCDAT0;该宏函数用来设置 ADC 控制寄存器启动 X 坐标的 A/D 转换,参考S3c2410 芯片 datasheet 中关于触摸屏的章节,具体设置参数如下:PRESCALE_EN=114*1A/D 转换器使能,设为 1 表示使能 A/D 转换器PRSCVL(4

35、9)=496A/D 转换器值,设为 49ADC_INPUT(ADC_IN5)=53 选择模拟输入通道,设为 5 表示 AIN5引脚作为模拟输入通道ADC_START_BY_RD_EN=11*1A/D 转换通过读启动, 设为 1 表示通过读操作启动A/D 转换使能ADC_NORMAL_MODE;=12*0 选择待命模式,设为 0 表示正常操作模式ADCDAT0;读取 X 坐标的 ADC 转换数据寄存器由于设置了 A/D 转换通过读启动,则该 ADCCON 寄存器的最低位ENABLE_START 启动A/D 转换位就无效了。在最后一步读取 ADCDAT0 寄存器这一操作时就启动了 A/D 转换。s

36、taticinlinevoids3c2410_get_XY(void)这就是获取 A/D 转换所得到的坐标值的函数。if(adc_state=0)adc_state=1;disable_ts_adc();y=(ADCDAT0&0 x3ff);mode_y_axis();start_adc_y();这里首先查看 A/D 转换的状态变量,若为 0 表示进行过 X 坐标的 A/D 转换,将该变量设为 1。然后调用宏函数 disable_ts_adc,该宏函数定义如下:#definedisable_ts_adc()ADCCON&=(ADCCON_READ_START);这个宏函数主要工

37、作就是禁止通过读操作启动 A/D 转换,参考 S3C2410芯片 datasheet 中关于触摸屏的章节,具体设置参数如下:ADCCON_READ_START=11A/D 转换通过读启动, 设为 0 表示通过读操作启动 A/D 转换禁止然后 y=(ADCDAT0&0 x3ff);这一步将 X 坐标的 ADC转换数据寄存器的 D9D0 这 10 为读出到变量 y(这里由于是竖屏,参考原理图后知道,硬件连线有过改动,将XP,XM 和YP,YM 进行了对换, 这样 ADCDAT0 里读出的是 YP,YM 方向电阻导通的值,也就是 y 轴坐标值)。这个 mode_y_axis 宏函数定义如下:

38、#definemode_y_axis()ADCTSC=XP_AIN|XM_HIZ|YP_EXTVLT|YM_GND|XP_PULL_UP_DIS|XP_PST(Y_AXIS_MODE);该宏函数用来设置 ADC 触摸屏控制寄存器为测量 Y 坐标模式,参考S3c2410 芯片 datasheet 中关于触摸屏的章节,具体设置参数如下:XP_AIN=14*1 选择 nXPON 引脚输出值,设为 1 表示 nXPON 引脚输出 1,则 XP 引脚连接 AIN7引脚XM_HIZ=15*0 选择 XMON 引脚输出值,设为 0 表示 XMON 引脚输出 0,则 XM 引脚为高阻态YP_EXTVLT=16

39、*0 选择 nYPON 引脚输出值, 设为 0 表示 nYPON 引脚输出 0,贝 UYP引脚为接外部电压YM_GND=17*1 选择 YMON 引脚输出值,设为 1 表示 YMON 引脚输出 1,则 YM 引脚为接地XP_PULL_UP_DIS=13*1 上拉开关使能,设为 1 表示 XP 引脚上拉禁止XP_PST(Y_AXIS_MODE);=2X 坐标丫坐标手动测量设置,设为 2 表示丫坐标测量模式最后调用 start_adc_y 宏函数,具体定义如下:#definestart_adc_y()ADCCON=PRESCALE_EN|PRSCVL(49)|ADC_INPUT(ADC_IN7)|

40、ADC_START_BY_RD_EN|ADC_NORMAL_MODE;ADCDAT1;该宏函数用来设置 ADC 控制寄存器启动 Y 坐标的 A/D 转换,参考S3c2410 芯片 datasheet 中关于触摸屏的章节,具体设置参数如下:PRESCALE_EN=114*1A/D 转换器使能,设为 1 表示使能 A/D 转换器PRSCVL(49)=496A/D 转换器值,设为 49ADC_INPUT(ADC_IN7)=73 选择模拟输入通道,设为 7 表示 AIN7引脚作为模拟输入通道ADC_START_BY_RD_EN=11*1A/D 转换通过读启动, 设为 1 表示通过读操作启动A/D 转换

41、使能ADC_NORMAL_MODE;=12*0 选择待命模式,设为 0 表示正常操作模式ADCDAT1;读取 Y 坐标的 ADC 转换数据寄存器elseif(adc_state=1)adc_state=0;disable_ts_adc();x=(ADCDAT1&0 x3ff);tsdev.penStatus=PEN_DOWN;DPRINTK(PENDOWN:x:%08d,y:%08dn,x,y);wait_up_int();tsEvent();若查看 A/D 转换的状态变量,若为 1 表示进行过 Y 坐标的 A/D 转换,将该变量设为 0。然后调用宏函数 disable_ts_adc

42、来禁止通过读操作启动 A/D 转换。接着将 x=(ADCDAT1&0 x3ff);这一步将 Y 坐标的 ADC 转换数据寄存器的D9D0 这 10 为读出到变量 x(这里由于是竖屏,参考原理图后知道,硬件连线有过改动,将 XP,XM 和 YP,YM 进行了对换,这样 ADCDAT1 里读出的是 XP,XM 方向电阻导通的值,也就是 x 轴坐标值)。随后将变量 tsdev.penStatus 的状态值改为笔按下,并调用 wait_up_int宏函数来设置触摸屏为等待中断模式【笔抬起产生中断】,具体定义如下:#definewait_up_int()ADCTSC=UP_INT|XP_PULL

43、_UP_EN|XP_AIN|XM_HIZ|YP_AIN|YM_GND|XP_PST(WAIT_INT_MODE);用该宏函数来设置 ADC 触摸屏控制寄存器,参考 S3C2410 芯片datasheet 中关于触摸屏的章节,具体设置参数如下:UP_INT=18*1 该位保留且应该设为 0,这里设为 1 不知道为什么【笔按下或笔抬起中断信号控制位,设为 1 表示笔抬起产生中断信号】XP_PULL_UP_EN=13*0 上拉开关使能, 设为 0表示 XP 引脚上拉使能选择nXPON 引脚输出值,设为 1 表示nXPON引脚输出 1,则 XP 引脚选择XMON 引脚输出值, 设为 0 表示 XMON

44、引脚输出 0,则 XM 引选择nYPON 引脚输出值,设为 1 表示nYPON引脚输出 1,则 YP 引脚选择 YMON 引脚输出值,设为 1 表示 YMON 引脚输出 1,则 YM 引XP_PST(WAIT_INT_MODE);=3X 坐标丫坐标手动测量设置,设为 3 表示等待中断模式最后调用函数指针 tsEvent所指向的函数。 在 s3c2410_get_XY函数里面,应该表示这个驱动的设备文件已经打开,在打开设备文件函数中,tsEvent函数指针就指向了 tsEvent_raw 这XP_AIN=14*1 连接 AIN7引脚XM_HIZ=15*0 脚为高阻态YP_AIN=16*1 连接

45、AIN5引脚YM_GND=1lock,flags);_wake_up_common(q,mode,nr,0);wq_read_unlock_irqrestore(&q-lock,flags);宏函数 wq_read_lock_irqsave 的作用主要就是保存 IRQ 和 FIQ 的中断使能状态,并禁止 IRQ 中断;而宏函数 wq_read_unlock_irqrestore 的作用就是恢复 IRQ 和 FIQ 的中断使能状态。现在可以得知_wake_up 这个函数的作用,它首先保存 IRQ 和 FIQ 的中断使能状态,并禁止IRQ 中断,接着调用_wake_up_common 函数

46、来唤醒等待 q 队列的进程,最后再恢复 IRQ和 FIQ 的中断使能状态。/* Thecorewakeupfunction.Non-exclusivewakeups(nr_exclusive=0)justwakeeverything* up.Ifitsanexclusivewakeup(nr_exclusive=small+venumber)thenwewakeallthe*non-exclusivetasksandoneexclusivetask.* Therearecircumstancesinwhichwecantrytowakeataskwhichhasalready* started

47、torunbutisnotinstateTASK_RUNNING.try_to_wake_up()returnszero* inthis(rare)case,andwehandleitbycontonuingtoscanthequeue.*/staticinlinevoid_wake_up_common(wait_queue_head_t*q,unsignedintmode,intnr_exclusive,constintsync)该函数的作用是唤醒在等待当前等待队列的进程。参数 q 表示要操作的等待队列,mode 表示要唤醒任务的状态,如 TASK_UNINTERRUPTIBLE 或TASK

48、_INTERRUPTIBLE 等。nr_exclusive 是要唤醒的互斥进程数目,在这之前遇到的非互斥进程将被无条件唤醒。sync表不?在/kernel/include/linux/wait.h 文件中:struct_wait_queue_headwq_lock_tlock;structlist_headtask_list;#ifWAITQUEUE_DEBUGlong_magic;long_creator;#endif;typedefstruct_wait_queue_headwait_queue_head_t;这是等待队列数据结后。*definewq_read_lock_irqsavesp

49、in_lock_irqsave*definewq_read_unlock_irqrestorespin_unlock_irqrestore看到这里可以知道其实宏函数 wq_read_lock_irqsave 和wq_read_unlock_irqrestore 等价于宏函数 spin_lock_irqsave 和 spin_unlock_irqrestore,并直接将自己的参数传了下去。在/kernel/include/linux/spinlock.h 文件中:/*Thesearethegenericversionsofthespinlocksandread-write*locks.*/#definespin_lock_irqsave(lock,flags)dolocal_irq_save(flags);spin_lock(lock);while(0)#definespin_unlock_irqrestore(lock,flags)dospin_unlock(lock);local_irq_restore(flags);while(0)在这

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论