久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

linux input輸入子系統(tǒng)分析《三》:S3C2440的觸摸屏驅(qū)動實(shí)例

 云將東游 2016-03-15

轉(zhuǎn)自:

http://blog.csdn.net/ielife/article/details/7800299

主要講述本人在學(xué)習(xí)Linux內(nèi)核input子系統(tǒng)的全部過程,,如有分析不當(dāng),,多謝指正。以下方式均可聯(lián)系,,文章歡迎轉(zhuǎn)載,,保留聯(lián)系信息,以便交流,。

郵箱:[email protected]

主頁:www.(愛嵌論壇——嵌入式技術(shù)學(xué)習(xí)交流)

博客:blog.csdn.net/ielife


1.1    本節(jié)閱讀前提

本節(jié)的說明建立在前兩節(jié)的基礎(chǔ)之上,,需要先閱讀如下兩篇章:

linux input輸入子系統(tǒng)分析《一》:初識input輸入子系統(tǒng)

linux input輸入子系統(tǒng)分析《二》:s3c2440ADC簡單驅(qū)動實(shí)例分析

1.2    觸摸屏工作原理

S3C2440的觸摸屏接口是4線電阻式觸摸屏接口,可以控制x,、y方向上的引腳(XP,、XM、YP,、YM)的變換,,S3C2440觸摸屏的硬件資源包括觸摸屏引腳和ADC轉(zhuǎn)換接口,可以使用寄存器組中的ADCTSC寄存器來操作觸摸屏引腳資源,,ADCCON寄存器來控制AD轉(zhuǎn)換功能,,由linux input輸入子系統(tǒng)分析《二》:s3c2440ADC簡單驅(qū)動實(shí)例分析中介紹的觸摸屏接口工作模式為4種,,這里我們只是用x/y方向自動轉(zhuǎn)換模式和等待中斷模式,。自動轉(zhuǎn)換模式用于轉(zhuǎn)換x方向和y方向的值到ADCDAT0和ADCDAT1中,等待中斷模式用于檢測觸摸屏的按下和抬起,,一般使用上升沿和下降沿觸發(fā)獲得觸摸屏事件,。

觸摸屏使用引腳的4個引腳XP、XM,、YP,、YM分別對應(yīng)S3C2440芯片的AIN7、AIN6、AIN5,、AIN4模擬輸入源,,其中按照linux input輸入子系統(tǒng)分析《二》:s3c2440ADC簡單驅(qū)動實(shí)例分析中的圖4和圖5可以看出AIN7接XP,AIN5接YP,,由此可得x和y坐標(biāo)的模擬信號由AIN5和AIN7引腳通過ADC轉(zhuǎn)換器產(chǎn)生,,產(chǎn)生的數(shù)據(jù)保存在ADCDAT0和ADCDAT1中。

1.3    驅(qū)動程序組成結(jié)構(gòu)

分析代碼前,,有必要了解驅(qū)動程序的組成結(jié)構(gòu),。

s3c2440ts_init()完成的功能:

使能adc的PCLK時鐘源

映射操作觸摸屏寄存器的地址

初始化寄存器

初始化輸入設(shè)備

填充輸入子系統(tǒng)設(shè)備結(jié)構(gòu)體input_dev

申請中斷IRQ_TS和IRQ_ADC

注冊輸入設(shè)備到輸入子系統(tǒng)中

s3c2440ts_exit()完成的功能:

注銷使用的系統(tǒng)資源

stylus_updown()完成的功能:

中斷處理程序,完成對觸摸屏按下和釋放的判斷

啟動ADC轉(zhuǎn)換

stylus_action()完成的功能:

ADC轉(zhuǎn)換程序

上報事件

touch_timer_fire()完成的功能:

ADC的子功能

1.4    代碼分析

代碼如下:

  1. /* 
  2.  * s3c2440 觸摸屏驅(qū)動程序 
  3.  * 
  4.  * Kevin Lee <www.> 
  5.  */  
  6.    
  7. #include<linux/kernel.h> /* 提供prink等內(nèi)核特有屬性 */  
  8. #include<linux/module.h> /* 提供模塊及符號接口*/  
  9. #include<linux/init.h> /* 設(shè)置段,,如_init,、_exit,設(shè)置初始化優(yōu)先級,,如__initcall */  
  10. #include<linux/wait.h> /* 等待隊(duì)列wait_queue */  
  11. #include<linux/interrupt.h> /* 中斷方式,,如IRQF_SHARED */  
  12. #include<linux/fs.h> /* file_operations操作接口等 */  
  13. #include<linux/clk.h> /* 時鐘控制接口,如struct clk */  
  14. #include<linux/miscdevice.h> /* 雜項(xiàng)設(shè)備 */  
  15. #include<asm/io.h> /* 提供readl,、writel */  
  16. #include<linux/irq.h> /* 提供中斷相關(guān)宏 */  
  17. #include<asm/irq.h> /* 提供中斷號,,中斷類型等,如IRQ_ADC中斷號 */  
  18. #include<asm/arch/regs-adc.h> /* 提供控制器的寄存器操作,,如S3C2410_ADCCON */  
  19. #include<asm/uaccess.h> /* 提供copy_to_user等存儲接口 */  
  20. #include<linux/input.h> /* 內(nèi)核輸入子系統(tǒng)操作接口 */  
  21. #include<linux/slab.h> /* kzalloc內(nèi)存分配函數(shù) */  
  22. #include<linux/time.h> /* do_gettimeofday時間函數(shù) */  
  23. #include<linux/timer.h> /* timer定時器 */  
  24.    
  25. /* 用于代碼的調(diào)試 */  
  26. #define CONFIG_S3C2440_TOUCHSCREEN__DEBUG 1  
  27.    
  28. /* 用于處理位操作 */  
  29. #define BITS_PER_LONG           32  
  30. #define BIT_MASK(nr)         (1UL << ((nr) %BITS_PER_LONG))  
  31. #define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)  
  32.    
  33. /* 定義一個宏WAIT4INT,,用于對ADCTSC觸摸屏控制寄存器進(jìn)行操作, 
  34.  * S3C2410_ADCTSC_YM_SEN等在內(nèi)核include/asm/arch/regs-adc.h中被定義 
  35.  */  
  36. #define WAIT4INT(x)    (((x)<<8) |S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | \  
  37.                     S3C2410_ADCTSC_XP_SEN |S3C2410_ADCTSC_XY_PST(3))  
  38.    
  39. /* 定義一個宏AUTOPST,,用于設(shè)置ADCTSC觸摸屏控制寄存器為自動轉(zhuǎn)換模式 */  
  40. #define AUTOPST    (S3C2410_ADCTSC_YM_SEN |S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \  
  41.                 S3C2410_ADCTSC_AUTO_PST |S3C2410_ADCTSC_XY_PST(0))  
  42.    
  43. /* 觸摸屏數(shù)據(jù)結(jié)構(gòu)體 */  
  44. struct ts_event {  
  45.        short pressure;              /* 是否按下 */  
  46.        short xp;        /*觸摸屏x坐標(biāo)值 */  
  47.        short yp;        /*觸摸屏y坐標(biāo)值 */  
  48. };  
  49.    
  50. /* 觸摸屏設(shè)備結(jié)構(gòu)體 */  
  51. struct s3c2440_ts {  
  52.        struct input_dev *input;/* 輸入子系統(tǒng)設(shè)備結(jié)構(gòu)體 */  
  53.        struct timer_list timer;/* 定時器,,用于ADC轉(zhuǎn)換操作 */  
  54.        struct ts_event tc;  /* ADC轉(zhuǎn)換的值的保存位置,也用于上報input子系統(tǒng)的數(shù)據(jù) */  
  55.        int pendown;          /* 判斷是否有按下 */  
  56.        int count;        /* 用于驅(qū)動去抖的計(jì)數(shù) */  
  57.        int shift;         /* 用于驅(qū)動去抖的基數(shù) */  
  58. };  
  59.    
  60. /* 定義觸摸屏設(shè)備結(jié)構(gòu)體 */  
  61. static struct s3c2440_ts *s3c2440_ts;  
  62.    
  63. /* 定義虛擬地址訪問硬件寄存器,,__iomem只是用于表示指針將指向I/O內(nèi)存 */  
  64. static void __iomem *base_addr;  
  65.    
  66. /* 定義adc時鐘,,通過adc_clock接口獲得adc輸入時鐘,adc轉(zhuǎn)換器需要 */  
  67. static struct clk *adc_clock;  
  68.    
  69. /* 申明外部定義的信號量,,adc.c中定義,,處理IRQ_ADC共享中斷引起的資源互斥 */  
  70. extern struct semaphore adc_lock;  
  71. //DECLARE_MUTEX(adc_lock);  
  72.    
  73. /* 處理觸摸屏的數(shù)據(jù)及事件上報,屬于中斷調(diào)用的函數(shù),,不能睡眠 */  
  74. static void touch_timer_fire(unsigned long data)  
  75. {  
  76.     /* 保存ADCDAT0及ADCDAT1的x,,y坐標(biāo)值 */  
  77.     unsigned long data0;  
  78.     unsigned long data1;  
  79.      
  80.     /* 禁止中斷,處理完數(shù)據(jù)再打開中斷 */  
  81.     set_irq_type(IRQ_TC, IRQT_NOEDGE);  
  82.     set_irq_type(IRQ_ADC, IRQT_NOEDGE);  
  83.    
  84.     /* 讀取ADCDAT0和ADCDAT1寄存器,,提取ADC轉(zhuǎn)換的x,,y坐標(biāo)值 */  
  85.     data0 = readl(base_addr + S3C2410_ADCDAT0);  
  86.     data1 = readl(base_addr + S3C2410_ADCDAT1);  
  87.    
  88.     /* 判斷ADCDAT0和ADCDAT1中的[15]位,[15]位為等待中斷模式下用于判斷筆尖是否有抬起或落下,,0=落下 */  
  89.     s3c2440_ts->pendown = (!(data0 &S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));  
  90.    
  91.     /* 當(dāng)觸摸屏處于被按下狀態(tài),,執(zhí)行下面代碼 */  
  92.     if (s3c2440_ts->pendown) {  
  93.            /*count不為0,,說明正在轉(zhuǎn)換,xp和yp往右移動shift(2)位是為了去抖 
  94.             * 需要結(jié)合stylus_action中斷函數(shù)來看,,當(dāng)count=4時,,才能認(rèn)為轉(zhuǎn)換結(jié)束, 
  95.             * 即最后所得的xp和yp是被計(jì)算4次的,,最終上報時需要除以4,,因此這里預(yù)先 
  96.             * 右移2位,相當(dāng)于乘以4 
  97.             */  
  98.            if(s3c2440_ts->count != 0) {  
  99.                   s3c2440_ts->tc.xp>>= s3c2440_ts->shift;  
  100.                   s3c2440_ts->tc.yp>>= s3c2440_ts->shift;  
  101.    
  102. /* 終端打印調(diào)試信息 */  
  103. #ifdef CONFIG_S3C2440_TOUCHSCREEN__DEBUG  
  104.             {  
  105.                    struct timeval tv;  
  106.                    do_gettimeofday(&tv);  
  107.                    printk(KERN_INFO"T: %06d, X: %03x, Y: %03x\n", (int)tv.tv_usec, s3c2440_ts->tc.xp,s3c2440_ts->tc.yp);  
  108.             }  
  109. #endif  
  110.               /*報告X,、Y的絕對坐標(biāo)值*/  
  111.               input_report_abs(s3c2440_ts->input,ABS_X, s3c2440_ts->tc.xp);  
  112.               input_report_abs(s3c2440_ts->input,ABS_Y, s3c2440_ts->tc.yp);  
  113.                
  114.               /*報告觸摸屏的狀態(tài),,1表明觸摸屏被按下*/  
  115.               input_report_abs(s3c2440_ts->input,ABS_PRESSURE, s3c2440_ts->tc.pressure);  
  116.                
  117.               /*報告按鍵事件,鍵值為1(代表觸摸屏對應(yīng)的按鍵被按下)*/  
  118.               input_report_key(s3c2440_ts->input,BTN_TOUCH, s3c2440_ts->pendown);  
  119.                
  120.               /*等待接收方受到數(shù)據(jù)后回復(fù)確認(rèn),,用于同步*/  
  121.               input_sync(s3c2440_ts->input);  
  122.        }  
  123.    
  124.         /* count=0執(zhí)行這里面的代碼,,ADC還沒有開始轉(zhuǎn)換 */  
  125.          s3c2440_ts->tc.xp = 0;  
  126.          s3c2440_ts->tc.yp = 0;  
  127.          s3c2440_ts->count = 0;  
  128.          s3c2440_ts->tc.pressure = 0;  
  129.    
  130.         /* 因?yàn)橛|摸屏是按下狀態(tài),ADC還沒有轉(zhuǎn)換,,需要啟動ADC開始轉(zhuǎn)換 
  131.          * 本句代碼是設(shè)置觸摸屏為自動轉(zhuǎn)換模式 
  132.          */  
  133.          writel(S3C2410_ADCTSC_PULL_UP_DISABLE| AUTOPST, base_addr + S3C2410_ADCTSC);  
  134.    
  135.         /* 啟動ADC轉(zhuǎn)換 */  
  136.          writel(readl(base_addr +S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr + S3C2410_ADCCON);  
  137.      } else {  
  138.         /* 執(zhí)行到這里說明按鍵沒有被按下或按鍵抬起,,count清0 */  
  139.         s3c2440_ts->count = 0;  
  140.    
  141.         /* 報告按鍵事件,給0值說明按鍵抬起 */  
  142.         input_report_key(s3c2440_ts->input,BTN_TOUCH, 0);  
  143.    
  144.         /* 報告按鍵事件,,給0值說明按鍵抬起 */  
  145.         input_report_abs(s3c2440_ts->input,ABS_PRESSURE, 0);  
  146.    
  147.         /* 用于同步事件處理層同步上報的按鍵和觸摸事件 */  
  148.         input_sync(s3c2440_ts->input);  
  149.    
  150.         /* 將觸摸屏重新設(shè)置為等待中斷狀態(tài),,等待觸摸屏被按下 */  
  151.         writel(WAIT4INT(0), base_addr +S3C2410_ADCTSC);  
  152.          
  153.         /* 觸摸屏抬起了,可以釋放信號量了 */  
  154.         up(&adc_lock);  
  155.      }  
  156.       
  157.      /* 使能中斷觸發(fā)條件,,IRQT_BOTHEDGE為使能上升沿和下降沿觸發(fā) */  
  158.      set_irq_type(IRQ_TC, IRQT_BOTHEDGE);  
  159.      set_irq_type(IRQ_ADC, IRQT_BOTHEDGE);  
  160. }  
  161.    
  162. /* 觸摸屏中斷服務(wù)程序,,觸摸屏按下或抬起時觸發(fā)執(zhí)行 */  
  163. static irqreturn_t stylus_updown(int irq, void *dev_id)  
  164. {  
  165.     /* 用于記錄ADC轉(zhuǎn)換后的值 */  
  166.     unsigned long data0;  
  167.     unsigned long data1;  
  168.    
  169.     /* 由于是中斷程序,所以不能使用down和down_interruptible,,會導(dǎo)致睡眠 */  
  170.     if (down_trylock(&adc_lock) == 0)  
  171.     {  
  172.         /* 讀取ADCDAT0和ADCDAT1,,用于判斷觸摸屏是否被按下 */  
  173.         data0 = readl(base_addr +S3C2410_ADCDAT0);  
  174.         data1 = readl(base_addr +S3C2410_ADCDAT1);  
  175.    
  176.         /* 判斷按鍵是否被按下 */  
  177.         s3c2440_ts->pendown = (!(data0 &S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));  
  178.    
  179.         /* 按鍵已經(jīng)按下 */  
  180.         if (s3c2440_ts->pendown)  
  181.             /* 啟動ADC開始轉(zhuǎn)換數(shù)據(jù) */  
  182.             touch_timer_fire(0);  
  183.     }  
  184.    
  185.     return IRQ_RETVAL(IRQ_HANDLED);  
  186. }  
  187.    
  188. /*ADC中斷服務(wù)程序,ADC啟動后被執(zhí)行 */  
  189. static irqreturn_t stylus_action(int irq, void *dev_id)  
  190. {  
  191.     /* 同上函數(shù) */  
  192.     unsigned long data0;  
  193.     unsigned long data1;  
  194.    
  195. #ifdef CONFIG_S3C2440_TOUCHSCREEN__DEBUG  
  196.        printk(KERN_ERR "%s() No.%dline:\n\r",__FUNCTION__,__LINE__);  
  197. #endif  
  198.    
  199.     /* 獲取觸摸屏的x,,y坐標(biāo)值 */  
  200.     data0 = readl(base_addr + S3C2410_ADCDAT0);  
  201.     data1 = readl(base_addr + S3C2410_ADCDAT1);  
  202.      
  203.     /* 既然按鍵按下了,,執(zhí)行到此ADC轉(zhuǎn)換也開始了,應(yīng)該取得x,,y坐標(biāo)值了 
  204.      * x=ADCDAT0[9:0],y=ADCDAT1[9:0],,count++,presssure設(shè)置為1 
  205.      */  
  206.     s3c2440_ts->tc.xp += data0 &S3C2410_ADCDAT0_XPDATA_MASK;  
  207.     s3c2440_ts->tc.yp += data1 &S3C2410_ADCDAT1_YPDATA_MASK;  
  208.     s3c2440_ts->count++;  
  209.     s3c2440_ts->tc.pressure = 1;  
  210.      
  211.     /* 如果count小于4,需要重啟設(shè)置自動轉(zhuǎn)換模式,,并進(jìn)行ADC轉(zhuǎn)換,,用于去抖 */  
  212.     if (s3c2440_ts->count <(1<<s3c2440_ts->shift)) {  
  213.            writel(S3C2410_ADCTSC_PULL_UP_DISABLE| AUTOPST, base_addr + S3C2410_ADCTSC);  
  214.            writel(readl(base_addr+ S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr + S3C2410_ADCCON);  
  215.     } else {  
  216.            /*到這里說明count=4,啟動定時器去執(zhí)行touch_timer_fire函數(shù)上報按鍵和觸摸事件*/  
  217.            mod_timer(&s3c2440_ts->timer,jiffies + HZ / 100);  
  218.            /*檢測觸摸屏抬起的中斷信號*/  
  219.            writel(WAIT4INT(1),base_addr + S3C2410_ADCTSC);  
  220.     }  
  221.    
  222.     return IRQ_HANDLED;  
  223. }  
  224.    
  225. /* 初始化ADC控制寄存器和ADC觸摸屏控制寄存器 */  
  226. static void adc_init(void)  
  227. {  
  228.     /* S3C2410_ADCCON_PRSCEN設(shè)置ADCCON的位[14]=1為使能A/D預(yù)分頻器 
  229.      * S3C2410_ADCCON_PRSCVL設(shè)置ADCCON的位[13:6]=32表示設(shè)置的分頻值,, 
  230.      * ADC的轉(zhuǎn)換頻率需要在2.5MHZ以下,,我們使用的ADC輸入時鐘為PCLK=50MHZ,,50MHZ/(49+1)=1MHZ,,滿足條件 
  231.      */  
  232.     writel(S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(49), base_addr + S3C2410_ADCCON);  
  233.    
  234.     /* 初始化ADC啟動或延時寄存器,,ADC轉(zhuǎn)換啟動延時值設(shè)置為0xffff */  
  235.     writel(0xffff, base_addr + S3C2410_ADCDLY);  
  236.    
  237.     /* 初始化ADC觸摸屏控制寄存器ADCTSC, 
  238.      * WAIT4INT(0)在上面定義,,引腳YM,、YP、XM,、XP的使能位位于ADCTSC的[7:4]位,, 
  239.      * 設(shè)置觸摸屏的工作狀態(tài)在[1:0]位,WAIT4INT(0)=11010011,, 
  240.      * 1101代表筆尖按下時發(fā)生觸摸屏中斷信號IRQ_TS給CPU,,0011表示XP上拉使能, 
  241.      * 使用正常ADC轉(zhuǎn)換,,轉(zhuǎn)換的方式為等待中斷模式 
  242.      * 原理圖見linux input輸入子系統(tǒng)分析《二》:s3c2440的ADC簡單驅(qū)動實(shí)例分析 
  243.      */  
  244.     writel(WAIT4INT(0), base_addr +S3C2410_ADCTSC);  
  245. }  
  246.    
  247. /*s3c2440觸摸屏驅(qū)動模塊加載程序,,做了以下工作 
  248.  * 獲得時鐘源、設(shè)置訪問觸摸屏控制器的虛擬地址并初始化觸摸屏控制器,、初始化中斷定時器,、 
  249.  * 填充input_dev結(jié)構(gòu)體(設(shè)備基本信息及事件信息)、注冊中斷,、注冊設(shè)備到input子系統(tǒng) 
  250.  */  
  251. static int __init s3c2440ts_init(void)  
  252. {  
  253.     struct input_dev *input_dev;  
  254.     int err = -ENOMEM;  
  255.      
  256.     s3c2440_ts = kzalloc(sizeof(structs3c2440_ts), GFP_KERNEL);  
  257.     /*給輸入設(shè)備申請空間,,input_allocate_device定義在input.h中*/  
  258.     input_dev = input_allocate_device();  
  259.     if (!s3c2440_ts || !input_dev)  
  260.            gotofail1;  
  261.    
  262.     /* 獲得adc的時鐘源,通過arch/arm/mach-s3c2410/clock.c獲得提供的時鐘源為PCLK */  
  263.     adc_clock = clk_get(NULL, "adc");  
  264.     if (!adc_clock)  
  265.     {  
  266.         printk(KERN_ERR "failed to get adcclock source\n");  
  267.         return -ENOENT;  
  268.     }  
  269.    
  270.     /* 在時鐘控制器中給adc提供輸入時鐘,,ADC轉(zhuǎn)換需要輸入時鐘 */  
  271.     clk_enable(adc_clock);  
  272.    
  273.     /* 使用ioremap獲得操作ADC控制器的虛擬地址 
  274.      * S3C2410_PA_ADC=ADCCON,,是ADC控制器的基地址,寄存器組的長度=0x1c 
  275.      */  
  276.     base_addr = ioremap(S3C2410_PA_ADC, 0x1c);  
  277.     if (base_addr == NULL)  
  278.     {  
  279.         printk(KERN_ERR "Failed to remapregister block\n");  
  280.         return -ENOMEM;  
  281.         goto fail1;  
  282.     }  
  283.    
  284.     /*初始化ADC控制寄存器和ADC觸摸屏控制寄存器*/  
  285.     adc_init();  
  286.      
  287.     /* 初始化定時器 */  
  288.     init_timer(&s3c2440_ts->timer);  
  289.     s3c2440_ts->timer.data = 1;  
  290.     s3c2440_ts->timer.function =touch_timer_fire;  
  291.         
  292.     /* 設(shè)置觸摸屏輸入設(shè)備的標(biāo)志,,注冊輸入設(shè)備成功進(jìn)入根文件系統(tǒng),,可以cat /proc/bus/input/devices查看其內(nèi)容*/  
  293.     input_dev->name          = "s3c2410Touchscreen";  /* 設(shè)備名稱 */  
  294.     input_dev->phys         ="s3c2440ts/input0"; /*  */  
  295.     input_dev->id.bustype    = BUS_HOST;                    /*總線類型 */     
  296.     input_dev->id.vendor     = 0x1;                /*經(jīng)銷商ID */  
  297.     input_dev->id.product    = 0x2;                /*產(chǎn)品ID */  
  298.     input_dev->id.version    = 0x0100;                   /*版本ID */  
  299.      
  300.     s3c2440_ts->shift = 2;  
  301.      
  302.     /*下面初始化輸入設(shè)備,即給輸入設(shè)備結(jié)構(gòu)體input_dev的成員設(shè)置值,。 
  303.     evbit字段用于描述支持的事件,,這里支持同步事件、按鍵事件,、絕對坐標(biāo)事件,, 
  304.     BIT宏實(shí)際就是對1進(jìn)行位操作,定義在linux/bitops.h中*/  
  305.     input_dev->evbit[0] = BIT_MASK(EV_SYN) |BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  
  306.      
  307.     /*keybit字段用于描述按鍵的類型,,在input.h中定義了很多,,這里用BTN_TOUCH類型來表示觸摸屏的點(diǎn)擊*/  
  308.     input_dev->keybit[BIT_WORD(BTN_TOUCH)] =BIT_MASK(BTN_TOUCH);  
  309.    
  310.     /*對于觸摸屏來說,使用的是絕對坐標(biāo)系統(tǒng),。這里設(shè)置該坐標(biāo)系統(tǒng)中X和Y坐標(biāo)的最小值和最大值(0-1023范圍) 
  311.     ABS_X和ABS_Y就表示X坐標(biāo)和Y坐標(biāo),,ABS_PRESSURE就表示觸摸屏是按下還是抬起狀態(tài)*/  
  312.     input_set_abs_params(input_dev, ABS_X, 0,0x3FF, 0, 0);  
  313.     input_set_abs_params(input_dev, ABS_Y, 0,0x3FF, 0, 0);  
  314.     input_set_abs_params(input_dev,ABS_PRESSURE, 0, 1, 0, 0);  
  315.    
  316.     /* 申請ADC中斷,AD轉(zhuǎn)換完成后觸發(fā),。這里使用共享中斷IRQF_SHARED是因?yàn)樵撝袛嗵栐贏DC驅(qū)動中也使用了,, 
  317.     最后一個參數(shù)1是隨便給的一個值,,因?yàn)槿绻唤o值設(shè)為NULL的話,中斷就申請不成功*/  
  318.     if(request_irq(IRQ_ADC, stylus_action,IRQF_SHARED | IRQF_SAMPLE_RANDOM, input_dev->name, s3c2440_ts))  
  319.     {  
  320.         printk(KERN_ERR "s3c2440_ts.c:Could not allocate ts IRQ_ADC !\n");  
  321.        err = -EBUSY;  
  322.        goto fail2;  
  323.     }  
  324.    
  325.     /*申請觸摸屏中斷,,對觸摸屏按下或提筆時觸發(fā)*/  
  326.     if(request_irq(IRQ_TC, stylus_updown,IRQF_SAMPLE_RANDOM, input_dev->name, s3c2440_ts))  
  327.     {  
  328.         printk(KERN_ERR "s3c2440_ts.c:Could not allocate ts IRQ_TC !\n");  
  329.        err = -EBUSY;  
  330.        goto fail2;  
  331.     }  
  332.    
  333.     /* 初始化完畢,,注冊輸入子系統(tǒng) */  
  334.     s3c2440_ts->input = input_dev;  
  335.     err =input_register_device(s3c2440_ts->input);  
  336.     if(err)  
  337.            gotofail3;  
  338.      
  339.     /* 設(shè)置中斷觸發(fā)條件,IRQT_BOTHEDGE為使能上升沿和下降沿觸發(fā) */  
  340.     set_irq_type(IRQ_TC, IRQT_BOTHEDGE);  
  341.     set_irq_type(IRQ_ADC, IRQT_BOTHEDGE);  
  342.      
  343.     return 0;  
  344.    
  345. fail3:  
  346.        free_irq(IRQ_TC, (void *)s3c2440_ts);  
  347.        free_irq(IRQ_ADC, (void *)s3c2440_ts);  
  348. fail2:  
  349.        iounmap(base_addr);  
  350. fail1:  
  351.        input_free_device(input_dev);  
  352.        kfree(s3c2440_ts);  
  353.    
  354.     return err;  
  355. }  
  356.    
  357. static void __exit s3c2440ts_exit(void)  
  358. {  
  359.     /* 屏蔽并釋放中斷 */  
  360.     disable_irq(IRQ_TC);  
  361.     disable_irq(IRQ_ADC);  
  362.     free_irq(IRQ_TC, (void *)s3c2440_ts);  
  363.     free_irq(IRQ_ADC, (void *)s3c2440_ts);  
  364.      
  365.     /* 注銷定時器 */  
  366.     del_timer_sync(&s3c2440_ts->timer);  
  367.    
  368.     /* 屏蔽和禁止adc時鐘 */  
  369.     if(adc_clock)  
  370.     {  
  371.         clk_disable(adc_clock);  
  372.         clk_put(adc_clock);  
  373.         adc_clock = NULL;  
  374.     }  
  375.    
  376.     /* 注銷觸摸屏輸入子系統(tǒng) */  
  377.    input_unregister_device(s3c2440_ts->input);  
  378.      
  379.     /* 釋放虛擬地址 */  
  380.     iounmap(base_addr);  
  381.      
  382.     /* 釋放觸摸屏設(shè)備結(jié)構(gòu)體 */  
  383.     kfree(s3c2440_ts);  
  384. }  
  385.    
  386. module_init(s3c2440ts_init);  
  387. module_exit(s3c2440ts_exit);  
  388.    
  389. MODULE_AUTHOR("KevinLee <www.>");  
  390. MODULE_DESCRIPTION("S3c2440TouchScreen Device Driver");  
  391. MODULE_VERSION("S3C2440TOUCHSCREEN 1.0");  
  392. MODULE_LICENSE("GPL");  

1.5    添加Makefile及編譯模塊

Mkaefile腳本如下:

  1. MODULENAME:= s3c2440_ts.o  
  2.    
  3. ifneq($(KERNELRELEASE),)  
  4. #call from kernel build system  
  5. obj-m      := $(MODULENAME)  
  6.    
  7. else  
  8. #KERNELDIR?= /lib/modules/$(shell uname -r)/build  
  9. KERNELDIR?= /work/system/linux-2.6.22.6  
  10. PWD       := $(shell pwd)  
  11. default:  
  12.        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  13. endif  
  14.    
  15. clean:  
  16.        rm -rf *.o *~ core .depend .*.cmd *.ko*.mod.c .tmp_versions module* Module* $(APPNAME)  
  17.    
  18. depend.depend dep:  
  19.        $(CC) $(CFLAGS) -M *.c > .depend  
  20.    
  21. ifeq(.depend,$(wildcard .depend))  
  22. include.depend  
  23. endif  

直接執(zhí)行make,,獲得s3c2440_ts.ko文件,,insmod進(jìn)入內(nèi)核,點(diǎn)擊觸摸屏可以看到驅(qū)動中打印的信息,。

insmod驅(qū)動模塊s3c2440_ts.ko之后,,還可以通過cat /proc/bus/input/devices來查看輸入設(shè)備在輸入子系統(tǒng)中的信息:

I:Bus=0019 Vendor=0001 Product=0002 Version=0100

N:Name="s3c2410 Touchscreen"

P:Phys=s3c2440ts/input0

S:Sysfs=/class/input/input0

U:Uniq=

H:Handlers=mouse0 event0 evbug

B:EV=b

B:KEY=400 0 0 0 0 0 0 0 0 0 0

B:ABS=1000003

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多