轉(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)分析《二》:s3c2440的ADC簡單驅(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)分析《二》:s3c2440的ADC簡單驅(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)分析《二》:s3c2440的ADC簡單驅(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 代碼分析
代碼如下:
- /*
- * s3c2440 觸摸屏驅(qū)動程序
- *
- * Kevin Lee <www.>
- */
-
- #include<linux/kernel.h> /* 提供prink等內(nèi)核特有屬性 */
- #include<linux/module.h> /* 提供模塊及符號接口*/
- #include<linux/init.h> /* 設(shè)置段,,如_init,、_exit,設(shè)置初始化優(yōu)先級,,如__initcall */
- #include<linux/wait.h> /* 等待隊(duì)列wait_queue */
- #include<linux/interrupt.h> /* 中斷方式,,如IRQF_SHARED */
- #include<linux/fs.h> /* file_operations操作接口等 */
- #include<linux/clk.h> /* 時鐘控制接口,如struct clk */
- #include<linux/miscdevice.h> /* 雜項(xiàng)設(shè)備 */
- #include<asm/io.h> /* 提供readl,、writel */
- #include<linux/irq.h> /* 提供中斷相關(guān)宏 */
- #include<asm/irq.h> /* 提供中斷號,,中斷類型等,如IRQ_ADC中斷號 */
- #include<asm/arch/regs-adc.h> /* 提供控制器的寄存器操作,,如S3C2410_ADCCON */
- #include<asm/uaccess.h> /* 提供copy_to_user等存儲接口 */
- #include<linux/input.h> /* 內(nèi)核輸入子系統(tǒng)操作接口 */
- #include<linux/slab.h> /* kzalloc內(nèi)存分配函數(shù) */
- #include<linux/time.h> /* do_gettimeofday時間函數(shù) */
- #include<linux/timer.h> /* timer定時器 */
-
- /* 用于代碼的調(diào)試 */
- #define CONFIG_S3C2440_TOUCHSCREEN__DEBUG 1
-
- /* 用于處理位操作 */
- #define BITS_PER_LONG 32
- #define BIT_MASK(nr) (1UL << ((nr) %BITS_PER_LONG))
- #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-
- /* 定義一個宏WAIT4INT,,用于對ADCTSC觸摸屏控制寄存器進(jìn)行操作,
- * S3C2410_ADCTSC_YM_SEN等在內(nèi)核include/asm/arch/regs-adc.h中被定義
- */
- #define WAIT4INT(x) (((x)<<8) |S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | \
- S3C2410_ADCTSC_XP_SEN |S3C2410_ADCTSC_XY_PST(3))
-
- /* 定義一個宏AUTOPST,,用于設(shè)置ADCTSC觸摸屏控制寄存器為自動轉(zhuǎn)換模式 */
- #define AUTOPST (S3C2410_ADCTSC_YM_SEN |S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
- S3C2410_ADCTSC_AUTO_PST |S3C2410_ADCTSC_XY_PST(0))
-
- /* 觸摸屏數(shù)據(jù)結(jié)構(gòu)體 */
- struct ts_event {
- short pressure; /* 是否按下 */
- short xp; /*觸摸屏x坐標(biāo)值 */
- short yp; /*觸摸屏y坐標(biāo)值 */
- };
-
- /* 觸摸屏設(shè)備結(jié)構(gòu)體 */
- struct s3c2440_ts {
- struct input_dev *input;/* 輸入子系統(tǒng)設(shè)備結(jié)構(gòu)體 */
- struct timer_list timer;/* 定時器,,用于ADC轉(zhuǎn)換操作 */
- struct ts_event tc; /* ADC轉(zhuǎn)換的值的保存位置,也用于上報input子系統(tǒng)的數(shù)據(jù) */
- int pendown; /* 判斷是否有按下 */
- int count; /* 用于驅(qū)動去抖的計(jì)數(shù) */
- int shift; /* 用于驅(qū)動去抖的基數(shù) */
- };
-
- /* 定義觸摸屏設(shè)備結(jié)構(gòu)體 */
- static struct s3c2440_ts *s3c2440_ts;
-
- /* 定義虛擬地址訪問硬件寄存器,,__iomem只是用于表示指針將指向I/O內(nèi)存 */
- static void __iomem *base_addr;
-
- /* 定義adc時鐘,,通過adc_clock接口獲得adc輸入時鐘,adc轉(zhuǎn)換器需要 */
- static struct clk *adc_clock;
-
- /* 申明外部定義的信號量,,adc.c中定義,,處理IRQ_ADC共享中斷引起的資源互斥 */
- extern struct semaphore adc_lock;
- //DECLARE_MUTEX(adc_lock);
-
- /* 處理觸摸屏的數(shù)據(jù)及事件上報,屬于中斷調(diào)用的函數(shù),,不能睡眠 */
- static void touch_timer_fire(unsigned long data)
- {
- /* 保存ADCDAT0及ADCDAT1的x,,y坐標(biāo)值 */
- unsigned long data0;
- unsigned long data1;
-
- /* 禁止中斷,處理完數(shù)據(jù)再打開中斷 */
- set_irq_type(IRQ_TC, IRQT_NOEDGE);
- set_irq_type(IRQ_ADC, IRQT_NOEDGE);
-
- /* 讀取ADCDAT0和ADCDAT1寄存器,,提取ADC轉(zhuǎn)換的x,,y坐標(biāo)值 */
- data0 = readl(base_addr + S3C2410_ADCDAT0);
- data1 = readl(base_addr + S3C2410_ADCDAT1);
-
- /* 判斷ADCDAT0和ADCDAT1中的[15]位,[15]位為等待中斷模式下用于判斷筆尖是否有抬起或落下,,0=落下 */
- s3c2440_ts->pendown = (!(data0 &S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
-
- /* 當(dāng)觸摸屏處于被按下狀態(tài),,執(zhí)行下面代碼 */
- if (s3c2440_ts->pendown) {
- /*count不為0,,說明正在轉(zhuǎn)換,xp和yp往右移動shift(2)位是為了去抖
- * 需要結(jié)合stylus_action中斷函數(shù)來看,,當(dāng)count=4時,,才能認(rèn)為轉(zhuǎn)換結(jié)束,
- * 即最后所得的xp和yp是被計(jì)算4次的,,最終上報時需要除以4,,因此這里預(yù)先
- * 右移2位,相當(dāng)于乘以4
- */
- if(s3c2440_ts->count != 0) {
- s3c2440_ts->tc.xp>>= s3c2440_ts->shift;
- s3c2440_ts->tc.yp>>= s3c2440_ts->shift;
-
- /* 終端打印調(diào)試信息 */
- #ifdef CONFIG_S3C2440_TOUCHSCREEN__DEBUG
- {
- struct timeval tv;
- do_gettimeofday(&tv);
- printk(KERN_INFO"T: %06d, X: %03x, Y: %03x\n", (int)tv.tv_usec, s3c2440_ts->tc.xp,s3c2440_ts->tc.yp);
- }
- #endif
- /*報告X,、Y的絕對坐標(biāo)值*/
- input_report_abs(s3c2440_ts->input,ABS_X, s3c2440_ts->tc.xp);
- input_report_abs(s3c2440_ts->input,ABS_Y, s3c2440_ts->tc.yp);
-
- /*報告觸摸屏的狀態(tài),,1表明觸摸屏被按下*/
- input_report_abs(s3c2440_ts->input,ABS_PRESSURE, s3c2440_ts->tc.pressure);
-
- /*報告按鍵事件,鍵值為1(代表觸摸屏對應(yīng)的按鍵被按下)*/
- input_report_key(s3c2440_ts->input,BTN_TOUCH, s3c2440_ts->pendown);
-
- /*等待接收方受到數(shù)據(jù)后回復(fù)確認(rèn),,用于同步*/
- input_sync(s3c2440_ts->input);
- }
-
- /* count=0執(zhí)行這里面的代碼,,ADC還沒有開始轉(zhuǎn)換 */
- s3c2440_ts->tc.xp = 0;
- s3c2440_ts->tc.yp = 0;
- s3c2440_ts->count = 0;
- s3c2440_ts->tc.pressure = 0;
-
- /* 因?yàn)橛|摸屏是按下狀態(tài),ADC還沒有轉(zhuǎn)換,,需要啟動ADC開始轉(zhuǎn)換
- * 本句代碼是設(shè)置觸摸屏為自動轉(zhuǎn)換模式
- */
- writel(S3C2410_ADCTSC_PULL_UP_DISABLE| AUTOPST, base_addr + S3C2410_ADCTSC);
-
- /* 啟動ADC轉(zhuǎn)換 */
- writel(readl(base_addr +S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr + S3C2410_ADCCON);
- } else {
- /* 執(zhí)行到這里說明按鍵沒有被按下或按鍵抬起,,count清0 */
- s3c2440_ts->count = 0;
-
- /* 報告按鍵事件,給0值說明按鍵抬起 */
- input_report_key(s3c2440_ts->input,BTN_TOUCH, 0);
-
- /* 報告按鍵事件,,給0值說明按鍵抬起 */
- input_report_abs(s3c2440_ts->input,ABS_PRESSURE, 0);
-
- /* 用于同步事件處理層同步上報的按鍵和觸摸事件 */
- input_sync(s3c2440_ts->input);
-
- /* 將觸摸屏重新設(shè)置為等待中斷狀態(tài),,等待觸摸屏被按下 */
- writel(WAIT4INT(0), base_addr +S3C2410_ADCTSC);
-
- /* 觸摸屏抬起了,可以釋放信號量了 */
- up(&adc_lock);
- }
-
- /* 使能中斷觸發(fā)條件,,IRQT_BOTHEDGE為使能上升沿和下降沿觸發(fā) */
- set_irq_type(IRQ_TC, IRQT_BOTHEDGE);
- set_irq_type(IRQ_ADC, IRQT_BOTHEDGE);
- }
-
- /* 觸摸屏中斷服務(wù)程序,,觸摸屏按下或抬起時觸發(fā)執(zhí)行 */
- static irqreturn_t stylus_updown(int irq, void *dev_id)
- {
- /* 用于記錄ADC轉(zhuǎn)換后的值 */
- unsigned long data0;
- unsigned long data1;
-
- /* 由于是中斷程序,所以不能使用down和down_interruptible,,會導(dǎo)致睡眠 */
- if (down_trylock(&adc_lock) == 0)
- {
- /* 讀取ADCDAT0和ADCDAT1,,用于判斷觸摸屏是否被按下 */
- data0 = readl(base_addr +S3C2410_ADCDAT0);
- data1 = readl(base_addr +S3C2410_ADCDAT1);
-
- /* 判斷按鍵是否被按下 */
- s3c2440_ts->pendown = (!(data0 &S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
-
- /* 按鍵已經(jīng)按下 */
- if (s3c2440_ts->pendown)
- /* 啟動ADC開始轉(zhuǎn)換數(shù)據(jù) */
- touch_timer_fire(0);
- }
-
- return IRQ_RETVAL(IRQ_HANDLED);
- }
-
- /*ADC中斷服務(wù)程序,ADC啟動后被執(zhí)行 */
- static irqreturn_t stylus_action(int irq, void *dev_id)
- {
- /* 同上函數(shù) */
- unsigned long data0;
- unsigned long data1;
-
- #ifdef CONFIG_S3C2440_TOUCHSCREEN__DEBUG
- printk(KERN_ERR "%s() No.%dline:\n\r",__FUNCTION__,__LINE__);
- #endif
-
- /* 獲取觸摸屏的x,,y坐標(biāo)值 */
- data0 = readl(base_addr + S3C2410_ADCDAT0);
- data1 = readl(base_addr + S3C2410_ADCDAT1);
-
- /* 既然按鍵按下了,,執(zhí)行到此ADC轉(zhuǎn)換也開始了,應(yīng)該取得x,,y坐標(biāo)值了
- * x=ADCDAT0[9:0],y=ADCDAT1[9:0],,count++,presssure設(shè)置為1
- */
- s3c2440_ts->tc.xp += data0 &S3C2410_ADCDAT0_XPDATA_MASK;
- s3c2440_ts->tc.yp += data1 &S3C2410_ADCDAT1_YPDATA_MASK;
- s3c2440_ts->count++;
- s3c2440_ts->tc.pressure = 1;
-
- /* 如果count小于4,需要重啟設(shè)置自動轉(zhuǎn)換模式,,并進(jìn)行ADC轉(zhuǎn)換,,用于去抖 */
- if (s3c2440_ts->count <(1<<s3c2440_ts->shift)) {
- writel(S3C2410_ADCTSC_PULL_UP_DISABLE| AUTOPST, base_addr + S3C2410_ADCTSC);
- writel(readl(base_addr+ S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr + S3C2410_ADCCON);
- } else {
- /*到這里說明count=4,啟動定時器去執(zhí)行touch_timer_fire函數(shù)上報按鍵和觸摸事件*/
- mod_timer(&s3c2440_ts->timer,jiffies + HZ / 100);
- /*檢測觸摸屏抬起的中斷信號*/
- writel(WAIT4INT(1),base_addr + S3C2410_ADCTSC);
- }
-
- return IRQ_HANDLED;
- }
-
- /* 初始化ADC控制寄存器和ADC觸摸屏控制寄存器 */
- static void adc_init(void)
- {
- /* S3C2410_ADCCON_PRSCEN設(shè)置ADCCON的位[14]=1為使能A/D預(yù)分頻器
- * S3C2410_ADCCON_PRSCVL設(shè)置ADCCON的位[13:6]=32表示設(shè)置的分頻值,,
- * ADC的轉(zhuǎn)換頻率需要在2.5MHZ以下,,我們使用的ADC輸入時鐘為PCLK=50MHZ,,50MHZ/(49+1)=1MHZ,,滿足條件
- */
- writel(S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(49), base_addr + S3C2410_ADCCON);
-
- /* 初始化ADC啟動或延時寄存器,,ADC轉(zhuǎn)換啟動延時值設(shè)置為0xffff */
- writel(0xffff, base_addr + S3C2410_ADCDLY);
-
- /* 初始化ADC觸摸屏控制寄存器ADCTSC,
- * WAIT4INT(0)在上面定義,,引腳YM,、YP、XM,、XP的使能位位于ADCTSC的[7:4]位,,
- * 設(shè)置觸摸屏的工作狀態(tài)在[1:0]位,WAIT4INT(0)=11010011,,
- * 1101代表筆尖按下時發(fā)生觸摸屏中斷信號IRQ_TS給CPU,,0011表示XP上拉使能,
- * 使用正常ADC轉(zhuǎn)換,,轉(zhuǎn)換的方式為等待中斷模式
- * 原理圖見linux input輸入子系統(tǒng)分析《二》:s3c2440的ADC簡單驅(qū)動實(shí)例分析
- */
- writel(WAIT4INT(0), base_addr +S3C2410_ADCTSC);
- }
-
- /*s3c2440觸摸屏驅(qū)動模塊加載程序,,做了以下工作
- * 獲得時鐘源、設(shè)置訪問觸摸屏控制器的虛擬地址并初始化觸摸屏控制器,、初始化中斷定時器,、
- * 填充input_dev結(jié)構(gòu)體(設(shè)備基本信息及事件信息)、注冊中斷,、注冊設(shè)備到input子系統(tǒng)
- */
- static int __init s3c2440ts_init(void)
- {
- struct input_dev *input_dev;
- int err = -ENOMEM;
-
- s3c2440_ts = kzalloc(sizeof(structs3c2440_ts), GFP_KERNEL);
- /*給輸入設(shè)備申請空間,,input_allocate_device定義在input.h中*/
- input_dev = input_allocate_device();
- if (!s3c2440_ts || !input_dev)
- gotofail1;
-
- /* 獲得adc的時鐘源,通過arch/arm/mach-s3c2410/clock.c獲得提供的時鐘源為PCLK */
- adc_clock = clk_get(NULL, "adc");
- if (!adc_clock)
- {
- printk(KERN_ERR "failed to get adcclock source\n");
- return -ENOENT;
- }
-
- /* 在時鐘控制器中給adc提供輸入時鐘,,ADC轉(zhuǎn)換需要輸入時鐘 */
- clk_enable(adc_clock);
-
- /* 使用ioremap獲得操作ADC控制器的虛擬地址
- * S3C2410_PA_ADC=ADCCON,,是ADC控制器的基地址,寄存器組的長度=0x1c
- */
- base_addr = ioremap(S3C2410_PA_ADC, 0x1c);
- if (base_addr == NULL)
- {
- printk(KERN_ERR "Failed to remapregister block\n");
- return -ENOMEM;
- goto fail1;
- }
-
- /*初始化ADC控制寄存器和ADC觸摸屏控制寄存器*/
- adc_init();
-
- /* 初始化定時器 */
- init_timer(&s3c2440_ts->timer);
- s3c2440_ts->timer.data = 1;
- s3c2440_ts->timer.function =touch_timer_fire;
-
- /* 設(shè)置觸摸屏輸入設(shè)備的標(biāo)志,,注冊輸入設(shè)備成功進(jìn)入根文件系統(tǒng),,可以cat /proc/bus/input/devices查看其內(nèi)容*/
- input_dev->name = "s3c2410Touchscreen"; /* 設(shè)備名稱 */
- input_dev->phys ="s3c2440ts/input0"; /* */
- input_dev->id.bustype = BUS_HOST; /*總線類型 */
- input_dev->id.vendor = 0x1; /*經(jīng)銷商ID */
- input_dev->id.product = 0x2; /*產(chǎn)品ID */
- input_dev->id.version = 0x0100; /*版本ID */
-
- s3c2440_ts->shift = 2;
-
- /*下面初始化輸入設(shè)備,即給輸入設(shè)備結(jié)構(gòu)體input_dev的成員設(shè)置值,。
- evbit字段用于描述支持的事件,,這里支持同步事件、按鍵事件,、絕對坐標(biāo)事件,,
- BIT宏實(shí)際就是對1進(jìn)行位操作,定義在linux/bitops.h中*/
- input_dev->evbit[0] = BIT_MASK(EV_SYN) |BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
- /*keybit字段用于描述按鍵的類型,,在input.h中定義了很多,,這里用BTN_TOUCH類型來表示觸摸屏的點(diǎn)擊*/
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] =BIT_MASK(BTN_TOUCH);
-
- /*對于觸摸屏來說,使用的是絕對坐標(biāo)系統(tǒng),。這里設(shè)置該坐標(biāo)系統(tǒng)中X和Y坐標(biāo)的最小值和最大值(0-1023范圍)
- ABS_X和ABS_Y就表示X坐標(biāo)和Y坐標(biāo),,ABS_PRESSURE就表示觸摸屏是按下還是抬起狀態(tài)*/
- input_set_abs_params(input_dev, ABS_X, 0,0x3FF, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0,0x3FF, 0, 0);
- input_set_abs_params(input_dev,ABS_PRESSURE, 0, 1, 0, 0);
-
- /* 申請ADC中斷,AD轉(zhuǎn)換完成后觸發(fā),。這里使用共享中斷IRQF_SHARED是因?yàn)樵撝袛嗵栐贏DC驅(qū)動中也使用了,,
- 最后一個參數(shù)1是隨便給的一個值,,因?yàn)槿绻唤o值設(shè)為NULL的話,中斷就申請不成功*/
- if(request_irq(IRQ_ADC, stylus_action,IRQF_SHARED | IRQF_SAMPLE_RANDOM, input_dev->name, s3c2440_ts))
- {
- printk(KERN_ERR "s3c2440_ts.c:Could not allocate ts IRQ_ADC !\n");
- err = -EBUSY;
- goto fail2;
- }
-
- /*申請觸摸屏中斷,,對觸摸屏按下或提筆時觸發(fā)*/
- if(request_irq(IRQ_TC, stylus_updown,IRQF_SAMPLE_RANDOM, input_dev->name, s3c2440_ts))
- {
- printk(KERN_ERR "s3c2440_ts.c:Could not allocate ts IRQ_TC !\n");
- err = -EBUSY;
- goto fail2;
- }
-
- /* 初始化完畢,,注冊輸入子系統(tǒng) */
- s3c2440_ts->input = input_dev;
- err =input_register_device(s3c2440_ts->input);
- if(err)
- gotofail3;
-
- /* 設(shè)置中斷觸發(fā)條件,IRQT_BOTHEDGE為使能上升沿和下降沿觸發(fā) */
- set_irq_type(IRQ_TC, IRQT_BOTHEDGE);
- set_irq_type(IRQ_ADC, IRQT_BOTHEDGE);
-
- return 0;
-
- fail3:
- free_irq(IRQ_TC, (void *)s3c2440_ts);
- free_irq(IRQ_ADC, (void *)s3c2440_ts);
- fail2:
- iounmap(base_addr);
- fail1:
- input_free_device(input_dev);
- kfree(s3c2440_ts);
-
- return err;
- }
-
- static void __exit s3c2440ts_exit(void)
- {
- /* 屏蔽并釋放中斷 */
- disable_irq(IRQ_TC);
- disable_irq(IRQ_ADC);
- free_irq(IRQ_TC, (void *)s3c2440_ts);
- free_irq(IRQ_ADC, (void *)s3c2440_ts);
-
- /* 注銷定時器 */
- del_timer_sync(&s3c2440_ts->timer);
-
- /* 屏蔽和禁止adc時鐘 */
- if(adc_clock)
- {
- clk_disable(adc_clock);
- clk_put(adc_clock);
- adc_clock = NULL;
- }
-
- /* 注銷觸摸屏輸入子系統(tǒng) */
- input_unregister_device(s3c2440_ts->input);
-
- /* 釋放虛擬地址 */
- iounmap(base_addr);
-
- /* 釋放觸摸屏設(shè)備結(jié)構(gòu)體 */
- kfree(s3c2440_ts);
- }
-
- module_init(s3c2440ts_init);
- module_exit(s3c2440ts_exit);
-
- MODULE_AUTHOR("KevinLee <www.>");
- MODULE_DESCRIPTION("S3c2440TouchScreen Device Driver");
- MODULE_VERSION("S3C2440TOUCHSCREEN 1.0");
- MODULE_LICENSE("GPL");
1.5 添加Makefile及編譯模塊
Mkaefile腳本如下:
- MODULENAME:= s3c2440_ts.o
-
- ifneq($(KERNELRELEASE),)
- #call from kernel build system
- obj-m := $(MODULENAME)
-
- else
- #KERNELDIR?= /lib/modules/$(shell uname -r)/build
- KERNELDIR?= /work/system/linux-2.6.22.6
- PWD := $(shell pwd)
- default:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- endif
-
- clean:
- rm -rf *.o *~ core .depend .*.cmd *.ko*.mod.c .tmp_versions module* Module* $(APPNAME)
-
- depend.depend dep:
- $(CC) $(CFLAGS) -M *.c > .depend
-
- ifeq(.depend,$(wildcard .depend))
- include.depend
- 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
|