Linux-2.6.32.2内核在mini2440上的移植(九).docx
1.inux-2.6.32.2内核在mini2440上的移植(九)-触摸屏驱动移植移植环境(缸色超字体字为修改於内容,道色粗体字为特殊待.&内容)1,主机环境:VMareFCentOS5.5,1G内存。2,集成开发环境:ElipseIDE3,编译编译环境:arm-linu×-gccv443.arm-none-li11u×-gnueab<-gccv4.5.1,4,开发板:mii2440.2Mnorflash.128Mnandflash,5,u-booi版本:u-tx>ot-2009.087.参考文堂:嵌入式IinUX应用开发完全手册,韦东山.编著.Mini2440之1.inUX移植开发实战指南博主黄刚嵌入式1.inux之我行S3C2440上ADCM动实例开发讲解1在内核中添加触摸屏骚动程序1.inux-2.6.32.2内核也没有包含支持S3C2440的触摸屏驱动,因此友善富方自行设计了*个s3c2410JSC它位linux-srG'drivers''input.ltouchscreenBIIF,你可以自己增加一个s3c2410js.c文件,并更制如下内容:/include<linuxerrno.h>#includeVllnUXykerneI.h>#include<linuxmodule.h>#include<linux.''slab.h>9Include<llnuxinput.h>#include<linuxinit.h>#include<linuxserio.h>tfinclude<linux.delay.h>includeVllnUXplatformdevlce.h>#include<linuj'clk.h>tfinclude<linux.gpio.h>#include<asml'lo.h>#include<asm>'irq.h>*include<platregs-adc.h>#include<machregsgpio.h>Forts.dev.id.version*/ffdefineS3C2410TSVERSION0x0101厂定义个WAIT4INT宏,该宗将对ADC触摸屏限制寄存满进行操作S3C2410_ADCTSC_YM_SEN这些宏祐定义在regs-adc.h>7*defineWA4INT(x)(<(x)<<8)|S3C2410_ADCTSC_YM_SENS3C2410_ADCTSC_YP_SEN|S3C2410_ADCTSC_XP_SEN|S3C2410_ADCTSC_XY_PST(3)tfdeflneAUTOPST(S3C2410_ADCTSC_YM_SENS3C2410_ADCTSCYP_SENS3C2410_ADCTSC_XP_SENS3C2410_ADCTSC_AUTO_PSTS3C2410_ADCTSC_XY_PST(0).'.staticchar*s3c2410ts-nam="s3c2410TouchScreen"defineDEVlCE_NAME“mlni2440JrOUChSCreen”广设备名称VstaticstructInpu1.dev,ts_dev;r定义一个输入设备来表示我们的肘擞屏设备7staticlongxp;staticlongyp;staticintcount;定义个外部的信号lADC_1.OCK.因为ADC,OCK在ADC!妪动程序中已申明这样就能保证ADC资源在ADC驱动和触摸屏驱动中进行互斥访问/externstructsemaphoreADC_1.OCK;staticintOwnADC=O;StatlcvoldIOmem*base_addr;/定义了一个用来保存钱过虚拟映射后的内存地址staticinlinevoids3c2410_ts_connect(void)(s3c2410gpiocfgpin(S3C2410_GPG(12),S3C2410_GPG12_XMON);S3c2410_gpio_cfgpin(S3C2410_GPG(13),S3C2410_GPG13_nXPON);s3c2410.gplocfgpln(S3C2410_GPG(14),S3C241O_GPG14YMON);s3c2410gpiocfgpin(S3C2410GPG(15),S3C2410GPG15nYP0N);staticvoidtouch_timer_fire(unsignedlongdata)(厂用于记录这一次AD转换后的值Vunsignedlongdata;unsignedlongdatal;intupdown;广用于记录触摸屏操作状态是按下还是抬起Vdata=ioread32(base_addr+S3C2410_ADCDAT0);data1=ioread32(baseaddr+S3C241O_ADCDAT1);广记录这一次对触摸屏是下还是抬起.该状态保存在数据寄存器的第15位.所以须要逻川与上S3C2410_ADCDATO_UPD0WN7updown=(!(data&S3C2410ADCDATOUPDOWN)&&(!(data1&S3C2410_ADCDAT0_UPDOWN);if(updown)厂推断触摸屏的操作状杳7(广假如状态是按下,并且ADC已经转换了就报告事务和数据7if(count!=O)转换四次后进行本务汇报(longtmp;tmp三xp;×P=YP;yp=tmp;这里进行折换是因为我们的屏林运用时采纳的是240-320,相当于把原来的屏弁的X,Y轴变换.个人理解.不知是否正确设备X,Y值XP»=2;yp»=2;华ifdefCONFIGJrOUCHSCREENMlNI244ODEBUG广触摸屏调试怡息.编译内核时选上此项后.点击触摸屏会在终端上打印出坐标信息Vstructtlmevaltv;do_gettimeofday(&tv);printk(KERN_DEBUG',T:%06d.X:%03ld,Y:%03ldnM,(int)tv.tv_usec,xp,yp);tfendifinputreportabs(tsdev,ABSX1xp);input_report_abs(ts_dev,ABS_Y,yp);门Il告按键事务.城值为1(代表触摸屏时应的按键被按下)/lnput_reporlkey(tsdev,BTN_TOUCH,1);广报告触摸屏的状态,1表明触摸屏被按卜/input_report_abs(ts_dev,ABS_PRESSURE,1);广等待接收方受到数据后1-1复确认,用于同步input_sync(ts_dev):这个表明我们上报一次完整的触摸屏事务.用来间隔下一次的报告广假如状态是按卜,并且ADC还没有起先转换就启动ADC进行转换Vxp=O;yp=;count=0;厂设置触摸屏的模式为自动转换模式/iwrlte32(S3C2410ADCTSCPU1.1.UPDISAB1.EAUTOPST,baseaddr+S3C2410_ADCTSC);厂启动ADC找换7iowrite32(ioread32(base-addr÷S3C2410-ADCCON)|S3C2410ADCCONENAB1.ESTART,baseaddr÷S3C2410ADCCON);假如还没有启动ADC或者ACD转换四次完毕后则启动ADCelse/*否则是抬起状态V假如贴UP状态,则提出报告并让触摸屏处在等待触摸的阶段count=0;input_report_key(ts_dev,BTN_TOUCH,0);门艮告按选名务,键值为0(代表触摸屏时应的按键被绛放门input_report_abs(ts_dev,ABS.PRESSURE,0);,报告触摸屏的状态,0表明触摸屏没被按下,input_sync(ts_dev);/*等待接收方受到数据后回我确认,用于同步*/lwrite32(WAIT4INT(0),baseaddr+S3C2410.ADCTSC);if(OwnADC)(OwnADC=0;up(&ADC_1.OCK);厂定义并初始化(一个定时器touchimer.定时器极务程序为touchJimeJfire/staticstructtimerJlstIouchJlmer三TIMERJNITIA1.IZER(touch_tlmerJlre,O,O);"DC中断眼芬程序,AD转换完成后触发执行Vstaticirqreturntstylusupdown(intirq,void'devoid)(unsignedlongdata;unsignedlongdata1;intupdown;留意在触摸屏驱动模块中,这个ADCJ_OCK的作用足保证任何时候都只行一个臾动程序运用ADC的中断线,因为在mini2440adc模块中也会运用到ADC,这样只有拥有了这个锁.才能进入到启动ADCIf(downtrylock(&ADC_1.OCK)=O)(OwnADC=1;data=Ioread32(baseaddr+S3C2410_ADCDAT0);data1=ioread32(baseaddr*S3C2410ADCDAT1);广记录这一次对触摸屏是压下还是拍起该状态保存在数据寄存器的第15位.所以须要逻辑与上S3C2410ADCDATOJJPDOWNrupdown=(!(data&S3C2410_ADCDAT0_UPDOWN)&&(!(data1&S3C2410_ADCDAT0_UPDOWN);if(updown)(t。UehImerjIre(O);/这是一个定时器函数,当然在这里是作为一般函数调用,用来只动ADCelse(OwnADC=0;up&ADC_1.OCK);留意这部分是基本不会执行的除非你触摸后以飞速的速度是否还来不及启动ADC,当然这种E速的速度一般是达不到的.考者调试程序时发觉这里是进入不了的returnIRQHAND1.ED;staticIrqreturnJstylus-action(intirq,void,devjd)(unsignedlongdata;unsignedlongdata1;If(OwnADC)1Udata=Ioread32(base.addr÷S3C2410.ADCDAT0);data1=ioread32(base_addr+S3C2410_ADCDAT1);xp÷=dataO&S3C2410ADCDATOXPDATAMASK;yp+=data1&S3C2410_ADCDAT1_YPDATA_MASK;count+;If(count<(1vv2)假如小如四次来新启动转换lowrlte32(S3C2410_ADCTSC_PU1.1.UPDISAB1.EAUTOPST,base_addr+S3C2410_ADCTSC):iowrite32(ioread32(base-addr÷S3C2410.ADCCON)S3C2410_ADCCON.ENAB1.ESTART,baseaddr÷S3C2410ADCCON);else假如超过四次,则等待ImS后进行数据上报mod_timer(&touch_timer,jiffies÷1);iowrite32(WAIT4INT(1)1base_addr+S3C2410.ADCTSC);returnIRQ_HAND1.ED;staticstructelkadc.clock;厂用于保存从平台时钟列衣中获得的ADC时钟/staticint_inits3c24IOtsJnit(Void)(structinput,dev,inputdev;广从平台时钟队列中获得ADC的时钟.这里为什么要取得这个时钟,因为ADC的转换版率跟时钟有关.系统的此时钟定义在archarm,'plat-s3c24xx/s3c2410-cbck.c1V*/adc_clock=clk_get(NU1.1.,"adc");if(!adc-clock)prlntk(KERN-ERR"failedtogetadcclocksourcen');return-ENOENT;广时钟获汨后要使能后才可以运用,clk_enable定义在ard'ar11Vplat-s3'cock.c中*/elkenable(adc_clock);获得时钟,挂载APBBUS上的外国设备.须要时钟限制.ADC就是这样的设备.NO内存是不能干脆进行访问的,必需对其进行映射.为Uo内存安排虚拟地址.这些虚拟地址以-JOmem进行说明,但不能腌对其进行访问,须要运用专用的函数,iowrite32S3C2410_PA_ADCADC限制器的她地址,定义在mach-s3c2410.'include/mach,'map.h中,0x20是虚拟地址长度大小7base_addr=ioremap(S3C2410_PA_ADC,0x20);If(baseaddr三=NU1.1.)printk(KERN_ERR"FailedtoremapregisterblocknM);return-ENOMEM;ConfigureGPIOs*/s3c2410_ts_ConneCt();iowrite32(S3C2410_ADCCON_PRSCENS3C2410_ADCCON_PRSCV1.(0xFF),baseaddr+S3C2410_ADCCON);使能预分频和设妣分频系数iowrite32(0xffff,base_addr+S3C2410_ADCD1.Y);/iWADC延时,在等待中断模式下表示产生INT_TC的间隔延时值为OXffffYWAIT4INT宏计算结果为(二进制):11010013再依据数据手册得知此处是将ADC触摸屏限制寄存器设置成等待中断模式/iwrite32(WAIT4INT(0),base_addr+S3C241(1.ADCTSC);/依据等待中断的模式设置TSCInitialiseinputstuff*1/allocatememoryfornewinputdevice,用来给蝌入设备安排空间,并做些怆入设的通用的初始的设附input_dev=input_allocate_device();H(!inPU1.deV)printk(KERN_ERR"Unabletoallocatetheinputdevice!In");return-ENOMEM;设置事务类型ts_dev三Input.dev;tsdev->evbit(O=BIT(EVSYN)BIT(EV_KEY)BIT(EV_ABS);ts_dev->keybitBITS_TO_1.ONGS(BTN_TOUCH)三BIT(BTN_TOUCH);input_set_abs_params(ts_dov,ABS_X,0,0x3FF,0,0);inputsetabsparams(tsdev,ABSY,0,0x3FF,0,0);input_set_abs_params(ts_dev,ABS-PRESSURE,0,1,0,0);广以上四句椰足我性事务类型中的COde如何理解呢,先说明事务类型,常用的事务类型EV_KEY.EV_MOSSE.EV_ABS(用来接像触摸屏这样的肯定坐标干务),而绿种田芬又会有不同类里的端码COde.比方说ABS_X.ABS_Y.这典编码又会有相应的VaIUe/ts-dev->name=DEVICE-NAME;ts_dev->ld.bustype三BUSRS232;ts_dev->id.vendor三OxDEAD;ts-dev->id.product=OxBEEF;ts-dev->id.vrsion=S3C2410TSVERSION;以上是输入设备的名称和汨,这些信息时输入设备的身份信息了,在用户空间如何看到呢?/"F以通过catrocbusi11putdevices.卜面"其输出信息root(3)mini2440,'#Catproc'bus'inputdevicsI:Bus=OOl3Vedor=deadProdUCt=beefVersion=OlOiN:Narne-s3c2410TouchScreen"P:Phys=S:SysfsTdevices/virtual/inpuUinputOU:UnIqH:Handlers=eventOB:EV=bB:KEY-OB:ABS=10000037Getirqs7中断处理/stylus-actio11stylus_updown两个中断处光.函数.巧笔尖触授时.会进入到StylUS_updownIf(requestJrq(IRQ.ADC,stylus_actlon,IRQF,SHAREDIRQF.SAMP1.ERANDOM,"s3c2410_action",ts_dev»(printk(KERN_ERR',s3c2410js.c:CouldnotallocatetsIRQ_ADC!n,');lounmap(baseaddr);return-EIO;If(requestirq(IRQ_TC,stylus_updown,IRQF_SAMP1.ERANDOM,"s3c2410_action",ts_dev)printk(KERN_ERR"s3c2410js.c:CouldnotallocatetsIRQ_TC!n");lounmap(baseaddr);return-EIO;printk(KERNJNFO',%ssuccessfullyIoadedn",s3c241Ots-name);Allwentok,soregistertotheinputsystem7的面己羟设猊/设备的基本信息和所具备的实力,全部的都打舞好了,现在就可以注册了Inputjegisterdevice(ts_dev);returnO;staticvoid_exits3c2410tsexit(void)disableJrq(IRQ_ADC);disableJrq(IRQTC);free_irq(IRQ_TC,ts_dev);free_irq(IRQ_ADC,ts_dev);if(adc_clock)elkdlsable(adc_clock);CIkJJUt(adjclock);adc_clockNU1.1.;input_unrogister_device(ts_dev);lounmap(baseaddr);moduleJnit(s3c241OtsJnit);moduleexlt(s3c241Otsexit);我们从整体上描述转换的过程:(1假如触摸屏感觉到触摸,则进入UPdoWnISR.假如能获得ADJ1.OCK则调用IouchJimerJire.启动ADC.(2)ADC转换.假如小于四次接著转换.假如四次完毕后,启动1个时间滴答的定时器.停止ADC.也就是说在这个时间滴答内,ADC是停止的,(3)这样可以防止屏舞抖动.(4)假如1个时间滴答到时候,触推屏仍旧处于触摸状态则上报转换数据,j(.A,:ADC,)ft(2)(5)假如触摸笔择放心则上报择放事务,并将触摸屏更新设置为等待中断状态.然后打开IinUX2632.2driversnpuVtouchscreenMakefiIe.定位到文件末尾.添加该被代码的目标模块,如下红色部分:obj$(CONFIG_TOUCHSCREEN_W90X900)+=v90p9l0js.ObjS(CQNFlGJoUCHSCREEh1.PCAP)+=pcapjs.oobj-$(CONFIG_TOUCHSCREEN_MINI2440)=s3c2410Js.it>Flinux-2.6.32.2/dnvers/inpuVtouchscreen.'KTOnfig.定位到14行旁边,加入如卜红色部分,这样就在内核配置中添加了mini2440的触摸解驱动选项:ifINPUT_TOUCHSCREENconfigTOUCHSCREEN_MINI2440tristate"SamsungS3C2440touchscreeninputdriver"dependsonMACH_MINI2440&&INPUT&&INPUT.TOUCHSCREEN&&MINI2440_ADCdefaultyhelpSayYhereifyouhavethes3c2440touchscreen.Ifunsure,sayN.Tocompilethisdriverasamodule,chooseMhere:themodulewillbecalleds3c241OJs.configTOUCHSCREENMY2440DEBUGboolean"S3C2440touchscreensinputdriverdebugmessages"dependsonTOUCHSCREEN_MINI2440helpSelectthisifyouwantdebugmessagesconfigTOUCHSCREEN-ADS746tristat"ADS7846,TSC2046andADS7843basedtouchscreens"dependsonSPI_MASTERdependsonHWMON=nHWMONhelp至此,我力就已经在内核中添加完了触摸疥驱动.2配置编译并启动内核在吩咐行执行:makemenuconfig.然后依次选择如下子菜单,找到刚刚添加的触摸屏驱动选琬DeviceDrivers>Inputdevicesupport->11Touchscreens>如图所示,按空格谟选中"S3C2440touchscreensinputdriverdebugmessages(NEW)“f摸屏驱动配置选项:退出并保存以上内核比置,在吩咐行输入:makeuimage.将生成archarm,boolulmage文件,然后现制到MsbooUkemeI出口下。启动开发板,可以在串口终始看到如下启动信息:mice:PS'2mousedevicecommonforallmicemini2440TouchScreensuccessfullyloadedinput:mini2440_TouchScreenasdeviceslvirtual'input'inputS3C24X×RTC.(c)2004,2006SimtecElectronics说明触摸屏的驱动加载胜利.(31创建触摸屏设备节点并测试新建一个测试文件,代码位于IinUX-test/COdetest,ItSteStC代码如Fj#include<stdio.h>*include<unistd.h>Include<stdllb.h>#include<ermo.h>include<sys.poll.h>tfinclude<fcntl.h>#include<stdio.h>include<stdlib.h>#Include<linuxlnput.h>structsamplecharposition15;intx;inty;structsamplesample-array4三(,topleft,0,01,toprighf',0,0,"botlonleft",O,O,Cbottonright",0,0,;intX1,X2,Y1,Y2;getsample(intfd,intposition)(structInputeventev128;intrb,sampl-cnt,cntx=O,cnty=O;rb=read(fd,ev,sizeof(structinput_event)*128):if(rb<(int)sizeof(structinput-evnt)perror("evtest:shortread");exit(1);for(sample-cnt=O;sample_cnt<(int)(rb.'slzeof(structlnputevent);!xiuo=cuo!i!sodeue-edujesI+>uoiane-u3edujes=÷(uosodejjeaduesKaP(XrhUO-adues=三S9V)I(!+X)U0ene-u-dujes=*-uo!)!SdXejjeadues)(p3u3-3dues3=-ssv)l!(;(ne-u3duesapoo(uoadues,9dX()U3-duesa',MP%anBp%poop%sdXj.Jguud!(09Sn-lU!hU3-dlUes9i00S-lU)U3dlUeS1.PI90%PI%Jud(0=03%lg-adues)j)(adAr11uo-adujes)a=S8V-3)I!(+juo-dusJ(1.)daas!(!,j)adujesja!(,.u,aseaajaseaddnsi»ui!i.)Huudt(9)deasi(uo!ysod!Xejje-adues',.uPUooaS9jojs%叫IPnOlasead“加ud(+!>!0=!)J(i(l)M×a!C,uojjuado,)ud)(0X(AnNoaa-Oi11OiueAOindui1Aeplal)Uado=PD)!三,p1,uu:PJdpjodIonJIS(6jb,.jeqa,ojeu)ueuu(!)JUJ1119Ji(Z-)(11e).03)-0=lJ(sxe=-SaV)l!(Z×-lX)(3X-anB).ow)-OW=jaj(saxB=ssv)l!9J,dUJ3U;)(SaXe)u'neu)eu!pjoo3-'s)u!X)U3=A'u!SdXejje-duesfor(l=0;l<4;l+)printf(',%12sx=%4d,y三44<fn'*.sample-arrayi.position,sample-arrayi.x,sample_arrayl.y);X1=(sample-array0.x÷sample-array2j.x)72;X2=(samplearray1.x+samplearray3.x)/2;Y1=(sample-array0.ysample_array1.y),'2;Y2三(sample-array2.y+sample_array3J.y).'2;printf("Coordinatecomplete.testitnown");for(i=0:i<4;i+)printf("Plasetouchthe%sfor6second!n",sample-arrayi.position);sleep(6);printf("TimeisupPleasereleases*');getsample(fd,i);sample_arrayi.x=ts_coordinate(sample_arrayi.x,ABS_X);sample_arrayl.y=ts_coordlnate(samplearray(l).y,ABSY);seep(1);printf("thedataaftercoordinaten");for(i=0;i<4;i+)prlntf("%12sx=>b4d,y=%4d,.n",samplearray(i.posltlon,sample-arrayi.x,sample_arrayi.y);)close(fd);exit(0);然后保存退出.(2在主.机终施交叉编译rootlocalhostcodetest#armlinuxgccotstesttstest.c将其更制到nfsboot书目下以使在开发板挂载该书目后能够执行rootlocalhostcodetest#cptstestnfsbUnfs(3查看设备信息由启动信息得知触摸屏设备为输入类设备,按如下操作:(rootmini2440/)#Calro'devicesCharacterdevices:1 mem2 ty3ttyp4 devvc05 tty6 .'dev4ty7 ZdevZconsoIe8 .,devptmx9 vcs10 misc13 input14 soundUr以得知输入类设需的主设符号为13.又按如下操作:(rootmini2440/)#catproc'businput.,devicesI:Bus=0013Vendor=deadProduct=befVersion=OIOIN:Name="mini2440_TOUChSCreen”P:Phys-S:Sysfs='devicesvirtual,'inpuVinputOU:Uniq=H:Handers三eventOB:EV=bB:KEY=OB:ABS=1000003rootmini2440可看查看总规的具体轮入设备输入设备的名称和id等具体的身份佐息恰息依据这些信息我们建立好设节点.设置内核调试级别为8.至干为什么设置内核调试级别为8,可以参考文章内核模块调试方法rootmini2440.'1#mkdir.'dev.,mput(rootmini2440/JSmknoddevnpuVeventOc1364rootmini2440/#echo8>pro,sys'kemeVprintk(rootmini2440p>cat,dev.'ipuVeventO然后打开触推屏设备,点击触控屏,出现如下伯息:棒N锹?愕N?棒N3悔NB棒N?m棒N尖?摄N璃棒N?W憎NC?他N_?帙N?X槎N?猫N?<NBe槎Nie馔N愠楞N精口N?菜N?菜N;?菜NO?菜N?N醛此时看不到打印的坐标信息,运行测试文件,可以看到如下信息:rootmini244Onfs#./tstestPleasetouchthetopleftfor6second!TimeisupPleaserelease1308931371.064677type3code0value9101308931373.034652type3code0value916Pleasetouchthetoprightfor6second!TimeisupPleaserelease1308931379.909666type3code1value9211308931380.059651type3code0value920Pleasetouchthebottonteftfor6second!TimeisupPleaserelease1308931387.144660type3code1value72Pleasetouchthebottonrightfor6send'TimeisupPleasereleasetopleftx=91l,y=82toprightx=920.y=920bottonleftx=101,y=72bottonrightX=98,y=945Coordinatecomplete,testitnowPleasetouchthetopleftfor6send!TimeisupPleaserelease1308931395.359705type3code1value944Pleasetouchthetoprightfor6second!TimeisupPleasereleasePleasetouchthebottonleftfor6secondITimeisupPleasereleasePleasetouchthebottonrightfor6second!TimeisupPleaserelease1308931421.859651type3code0value971308931421.979651type3code0value971308931422.084660type3code1value937thedataaftercoordinatetopleftx=14480,y=21165IOprightx=45920,y=28480bottonleftx-30560,y-17920bottonrightx=-32400.y=22034(rootmini2440nfs#有关松推屏疆动原理详解道参见Mni2440触换排程序分析.接下来,将进行USB外设配置.