第12章linux字符設(shè)備驅(qū)動(dòng)綜合實(shí)例_第1頁(yè)
第12章linux字符設(shè)備驅(qū)動(dòng)綜合實(shí)例_第2頁(yè)
第12章linux字符設(shè)備驅(qū)動(dòng)綜合實(shí)例_第3頁(yè)
第12章linux字符設(shè)備驅(qū)動(dòng)綜合實(shí)例_第4頁(yè)
第12章linux字符設(shè)備驅(qū)動(dòng)綜合實(shí)例_第5頁(yè)
已閱讀5頁(yè),還剩36頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例第 12 章Linux 字符驅(qū)動(dòng)綜合實(shí)例本章將分析 5 個(gè)典型的字符所講解的內(nèi)容。驅(qū)動(dòng),在這些驅(qū)動(dòng)中,將靈活地運(yùn)用到前面各章12.1 節(jié)講解按鍵的斷、定時(shí)器等相關(guān)12.2 節(jié)講解觸摸屏的些,但是很類似。驅(qū)動(dòng),加深讀者對(duì)字符。驅(qū)動(dòng)架構(gòu)、阻塞與非阻塞、中驅(qū)動(dòng),觸摸屏的驅(qū)動(dòng)比按鍵的驅(qū)動(dòng)稍微復(fù)雜一12.3 節(jié)講解 TI 的 DSP 提供給通用 CPU 的 HPI(主機(jī)并行接口)的件結(jié)構(gòu)為 ARM+DSP,ARM 的總線連接 DSP 的 HPI 接口。驅(qū)動(dòng),硬12.4 節(jié)講解通用 NVRAM 的雜)。驅(qū)動(dòng),并會(huì)引入一個(gè)新的概念,即 misc

2、device(混12.5 節(jié)講解看門狗的驅(qū)動(dòng),它也被歸入 miscdevice,這一節(jié)還會(huì)引入兩個(gè)新的概念,即 platform_device(平臺(tái))和 platform_driver(平臺(tái)驅(qū)動(dòng))。NVRAM 和看門狗的驅(qū)動(dòng)與普通字符驅(qū)動(dòng)有細(xì)微的差別。學(xué)院華清遠(yuǎn)見旗下品牌:Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例12.1.1按鍵的硬件原理在系統(tǒng)中,按鍵的硬件原理比較簡(jiǎn)單,通過一個(gè)上拉電阻將處理器的外部中斷(或 GPIO)引腳,電阻的另一端連接按鈕并接地即可實(shí)現(xiàn)。如圖 12.1 所示,當(dāng)按鈕被按下時(shí),EINT10、EIN13、EINT14、EINT15 上將產(chǎn)生低電平,這

3、個(gè)低電平將中斷 CPU(圖中的 CPU 為 S3C2410),CPU 可以依據(jù)中斷按鍵被按下。但是,僅僅依據(jù)中斷被產(chǎn)生就認(rèn)定有一次按鍵行為是很確的,所有按鍵、觸摸屏等機(jī)械都一個(gè)固有的,那就是“抖動(dòng)”,按鍵從最初接通到接通要經(jīng)過數(shù)毫秒,其間可能發(fā)生多次“接通斷開”的過程。如果不消除“抖動(dòng)”的影響,一次按鍵可能被理解為多次按鍵。消除按鍵抖動(dòng)影響的是:在有鍵按下后,進(jìn)行延時(shí)(如 20ms,在延時(shí)過程中要對(duì)應(yīng)中斷),再鍵盤狀態(tài),如果仍處于按鍵按下狀態(tài),則可以斷定該按鍵被按入功能,則可以改為完全12.2(a)所示。如果按鍵對(duì)應(yīng)的引身不具備中斷輸方式,流12.2(b)所示。圖 12.1 按鍵的硬件原理學(xué)院

4、華清遠(yuǎn)見旗下品牌:按鍵的驅(qū)動(dòng)Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例圖 12.2 確認(rèn)按鍵的流程按鍵驅(qū)動(dòng)中的數(shù)據(jù)結(jié)構(gòu)12.1.2驅(qū)動(dòng)中主要要設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu)是結(jié)構(gòu)體,按鍵的結(jié)構(gòu)體中應(yīng)包含一個(gè)緩沖區(qū),因?yàn)槎啻伟存I可能無法被及時(shí)處理,可以用該緩沖區(qū)緩存按鍵。此外,在按鍵結(jié)構(gòu)體中,還包含按鍵狀態(tài)標(biāo)志和一個(gè)實(shí)現(xiàn)過程中要借助的等待隊(duì)列、cdev結(jié)構(gòu)體。為了實(shí)現(xiàn)延時(shí),定時(shí)器也是必要的,但可以不包含在結(jié)構(gòu)體中。代碼12.1 給出了按鍵代碼結(jié)構(gòu)體及定時(shí)器。12.1 按鍵驅(qū)動(dòng)的結(jié)構(gòu)體、定時(shí)器在按鍵值,如代碼驅(qū)動(dòng)中,可用一個(gè)結(jié)構(gòu)體每個(gè)按鍵所對(duì)應(yīng)的中斷/GPIO 引腳及鍵12.2 所示。代碼1

5、2.2 按鍵硬件、鍵值信息結(jié)構(gòu)體學(xué)院華清遠(yuǎn)見旗下品牌:1 static struct key_info 2 3 int irq_no;/中斷號(hào)4 unsigned int gpio_port; /GPIO 端口5 int key_no;/鍵值6 key_info_tab4 = 7 8/*按鍵所使用的 CPU*/91 #define MAX_KEY_BUF 16 /按鍵緩沖區(qū)大小2 typedef unsigned char KEY_RET;3 /結(jié)構(gòu)體:4 typedef struct 5 6 unsigned int keyStatusKEY_NUM; /4 個(gè)按鍵的按鍵狀態(tài)7 KEY_RE

6、T bufMAX_KEY_BUF; /按鍵緩沖區(qū)8 unsigned int head, tail; /按鍵緩沖區(qū)頭和尾9 wait_queue_head_t wq; /等待隊(duì)列10 struct cdev cdev;/cdev 結(jié)構(gòu)體10 KEY_DEV;11 static struct timer_list key_timerKEY_NUM;/4 個(gè)按鍵去抖定時(shí)器Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例按鍵驅(qū)動(dòng)的文件操作結(jié)構(gòu)體如代碼12.3 所示,主要實(shí)現(xiàn)了打開、和讀函數(shù),因?yàn)榘存I只是一個(gè)輸入,所以不寫函數(shù)。代碼12.3 按鍵驅(qū)動(dòng)文件操作結(jié)構(gòu)體1 static st

7、ruct file_operations s3c2410_key_fops = 2 3 owner: THIS_MODULE,4 open: s3c2410_key_open, /啟動(dòng)5 release: s3c2410_key_release,6 read: s3c2410_key_read, / 7 ;/關(guān)閉 按鍵的鍵值12.1.3按鍵驅(qū)動(dòng)的模塊加載和卸載函數(shù)按鍵作為一種字符,在其模塊加載和卸載函數(shù)中分別包含了號(hào)申請(qǐng)和、cdev 的添加和刪除行為,在模塊加載函數(shù)中,還需申請(qǐng)中斷、初始化定時(shí)器和等待隊(duì)列等,模塊卸載函數(shù)完成相反的行為,代碼12.4 和 12.5 分別給出了按鍵驅(qū)動(dòng)的模塊加載和

8、卸載函數(shù),代碼12.6 和 12.7 分別給出了模塊加載和卸載所調(diào)用的申請(qǐng)和4 個(gè)中斷的函數(shù)。代碼12.4 按鍵驅(qū)動(dòng)的模塊加載函數(shù)static int init s3c2410_key_init(void)123456789101112131415./申請(qǐng)?zhí)?,添?cdevrequest_irqs(); /中斷函數(shù)keydev.head = keydev.tail = 0; /初始化結(jié)構(gòu)體for (i = 0; i < KEY_NUM; i+)keydev.keyStatusi = KEYSTATUS_UP; init_waitqueue_head(&(keydev.wq); /

9、等待隊(duì)列/初始化定時(shí)器,實(shí)現(xiàn)的去抖動(dòng)for (i = 0; i < KEY_NUM; i+) setup_timer(&key_timeri, key_timer_handler, i);/把按鍵的序號(hào)作為傳入定時(shí)器處理函數(shù)的參數(shù)代碼12.5 按鍵驅(qū)動(dòng)的模塊卸載函數(shù)學(xué)院華清遠(yuǎn)見旗下品牌:10IRQ_EINT10, GPIO_G2, 1 11 12 ,13 14IRQ_EINT13, GPIO_G5, 2 15 16 ,17 18IRQ_EINT14, GPIO_G6, 3 19 20 ,21 22IRQ_EINT15, GPIO_G7, 4 23 24 ,25 ;驅(qū)動(dòng)開發(fā)詳解第

10、12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例Linux代碼12.6按鍵驅(qū)動(dòng)的中斷申請(qǐng)函數(shù)12.7代碼按鍵驅(qū)動(dòng)的中斷函數(shù)12.1.4按鍵驅(qū)動(dòng)中斷、定時(shí)器處理程序在鍵被按下后,將發(fā)生中斷,在中斷處理,應(yīng)該關(guān)閉中斷進(jìn)入模式,延遲 20ms 以實(shí)現(xiàn)去抖動(dòng),如代碼12.8 所示,這個(gè)中斷處理過程只包含頂半部,無底半部。代碼12.8 按鍵驅(qū)動(dòng)的中斷處理程序在定時(shí)器處理,按鍵是否仍然被按下,如果是被按下的狀態(tài),則將該學(xué)院華清遠(yuǎn)見旗下品牌:1 static void s3c2410_eint_key(int irq, void *dev_id, struct pt_regs*reg)2 3 int key = de

11、v_id;4 disable_irq(key_info_tabkey.irq_no); /關(guān)中斷,轉(zhuǎn)入模式56 keydev.keyStatuskey = KEYSTATUS_DOWNX;/狀態(tài)為按下7 key_timerkey.expires = jiffies + KEY_TIMER_DELAY1;/延遲8 add_timer(&key_timerkey); /啟動(dòng)定時(shí)器9 1 /*中斷*/2 static void free_irqs(void) 3 4 struct key_info *k;5 int i;6 for (i = 0; i < sizeof(key_info

12、_tab) / sizeof(key_info_tab1); i+) 78 k = key_info_tab + i;9 free_irq(k->irq_no, buttons_irq); /中斷10 11 1 /*申請(qǐng)系統(tǒng)中斷,中斷方式為下降沿觸發(fā)*/2 static int request_irqs(void) 3 4 struct key_info *k;5 int i;6 for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab1); i+) 78 k = key_info_tab + i;9 set_extern

13、al_irq(k->irq_no, EXT_LOWLEVEL, GPIO_PULLUP_DIS);10 /設(shè)置低電平觸發(fā)11 if (request_irq(k->irq_no, &buttons_irq, SA_INTERRUPT, DEVICE_NAME,12 i) /申請(qǐng)中斷,將按鍵序號(hào)作為參數(shù)傳入中斷服務(wù)程序1314return - 1;1516 17 return 0; 18 1 static void exit s3c2410_key_exit(void) 2 3 free_irqs(); /注銷中斷4 ./號(hào),刪除 cdev5 Linux驅(qū)動(dòng)開發(fā)詳解第 12

14、章、Linux 字符驅(qū)動(dòng)綜合實(shí)例按鍵入緩沖區(qū)。同時(shí)啟動(dòng)新的定時(shí)器延遲,延遲一個(gè)相對(duì)于去抖更長(zhǎng)的時(shí)間(如100ms),每次定時(shí)器到期后,按鍵是否仍然處于按下狀態(tài),如果是,則重新啟用新的 100ms 延遲;若到已經(jīng)沒有按下,則認(rèn)定鍵已抬起,這個(gè)時(shí)候應(yīng)該開啟對(duì)應(yīng)按鍵的中斷,等待新的按鍵。每次新的鍵值時(shí),應(yīng)喚醒等待隊(duì)列。定時(shí)器處理流12.3 所示,代碼代碼如 12.9 所示。12.9按鍵驅(qū)動(dòng)的定時(shí)器處理函數(shù)學(xué)院華清遠(yuǎn)見旗下品牌:1 static void key_timer_handler(unsigned long data) 2 3 int key = data;4 if (ISKEY_DOWN(

15、key) 56 if (keydev.keyStatuskey = KEYSTATUS_DOWNX)7 /從中斷進(jìn)入89 keydev.keyStatuskey = KEYSTATUS_DOWN;10 key_timerkey.expires = jiffies + KEY_TIMER_DELAY; /延遲11 keyEvent(); /鍵值,喚醒等待隊(duì)列12 add_timer(&key_timerkey); 1314else1516 key_timerkey.expires = jiffies + KEY_TIMER_DELAY; /延遲17 add_timer(&key_

16、timerkey); 1819 20 else/鍵已抬起21 22 keydev.keyStatuskey = KEYSTATUS_UP;23 enable_irq(key_info_tabkey.irq_no); 24 25 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例圖 12.3 定時(shí)器處理函數(shù)流程12.1.5按鍵驅(qū)動(dòng)的打開、函數(shù)按鍵驅(qū)動(dòng)的打開和函數(shù)比較簡(jiǎn)單,主要是設(shè)置 keydev.head、keydev.tail和按鍵函數(shù)指針 keyEvent 的值,如代碼12.10 所示。代碼12.10 按鍵驅(qū)動(dòng)的打開、函數(shù)12.1.6按鍵驅(qū)動(dòng)讀函數(shù)代碼12.11 給出了按鍵驅(qū)動(dòng)

17、的讀函數(shù),按鍵驅(qū)動(dòng)的讀函數(shù)主要提供對(duì)按鍵結(jié)構(gòu)體中緩沖區(qū)的讀并到用戶空間。當(dāng) keydev.head ! = keydev.tail 時(shí),意味著緩沖區(qū)有數(shù)據(jù),使用 copy_to_user()拷貝到用戶空間,否則,根據(jù)用戶空間是阻塞讀還是非阻塞讀,分為如下兩種情況。l 若采用非阻塞讀,則因?yàn)闆]有按鍵緩存,直接返回- EAGAIN;l 若采用阻塞讀,則在 keydev.wq 等待隊(duì)列上睡眠,直到有按鍵被區(qū)后被喚醒。入緩沖代碼12.11 按鍵驅(qū)動(dòng)的讀函數(shù)1 static ssize_t s3c2410_key_read(struct file *filp, char *buf, ssize_t co

18、unt,loff_t*ppos)2345678910111213141516171819202122retry: if (keydev.head != keydev.tail)/當(dāng)前循環(huán)隊(duì)列中有數(shù)據(jù)key_ret = keyRead(); /按鍵copy_to_user(.); /把數(shù)據(jù)從內(nèi)核空間傳送到用戶空間elseif (filp->f_flags &O_NONBLOCK)/若用戶采用非阻塞方式return - EAGAIN;interruptible_sleep_on(&(keydev.wq);/用戶采用阻塞方式,調(diào)用該函數(shù)使進(jìn)程睡眠goto retry;retur

19、n 0;學(xué)院華清遠(yuǎn)見旗下品牌:1 static int s3c2410_key_open(struct inode *inode, struct file *filp) 2 3 keydev.head = keydev.tail = 0; /清空按鍵動(dòng)作緩沖區(qū)4 keyEvent = keyEvent_raw; /函數(shù)指針指向按鍵處理函數(shù) keyEvent_raw5 return 0;6 78 static int s3c2410_key_release(struct inode *inode, struct file*filp)9 10 keyEvent = keyEvent_dummy;

20、/函數(shù)指針指向空函數(shù)11 return 0; 12 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例最后,解釋一下代碼12.9 第 11 行的 keyEvent()函數(shù)和代碼12.11 的keyRead()函數(shù)。在驅(qū)動(dòng)的打開函數(shù)中,keyEvent 被賦值為 keyEvent_raw,這個(gè)函數(shù)完成鍵值,并使用 wait_up_interrupt(&(keydev.wq)語(yǔ)句喚醒 s3c2410_key_read()第 17 行所期待的等待隊(duì)列。而 keyRead()函數(shù)則直接從按鍵緩沖區(qū)中鍵值。12.2.1觸摸屏的硬件原理按照觸摸屏的工作原理和傳輸信息的介質(zhì),我們把觸摸

21、屏分為 4 種:電阻式、電容感應(yīng)式、紅外線式以及表面聲波式。電阻式觸摸屏利用感應(yīng)進(jìn)行,包含上下疊合的兩個(gè)透明層,通常還要用一種彈性材料來將兩層隔開。在觸摸某點(diǎn)時(shí),兩層會(huì)在此點(diǎn)接通。四線和八線觸摸屏由兩層具有相同表面電阻的透明阻性材料組成,五線和七線觸摸屏由一個(gè)阻性層和一個(gè)導(dǎo)電層組成。所有的電阻式觸摸屏都采用分壓器原理來產(chǎn)生代表 X 坐標(biāo)和 Y 坐標(biāo)的電壓。如圖12.4 所示,分壓器是通過將兩個(gè)電阻進(jìn)行串聯(lián)來實(shí)現(xiàn)的。電阻R1 連接正參考電壓VREF,電阻 R2 接地。兩個(gè)電阻連接點(diǎn)處的電壓測(cè)量值與 R2 的阻值成正比。為了在電阻式觸摸屏上的特定方向測(cè)量一個(gè)坐標(biāo),需要對(duì)一個(gè)阻性層進(jìn)行偏置:將它的一

22、邊接 VREF,另一邊接地。同時(shí),將未偏置的連接到一個(gè) ADC 的高阻抗輸入端。當(dāng)觸摸屏上的足夠大,兩層之間發(fā)生接觸時(shí),電阻性表面被分隔為兩個(gè)電阻。它們的阻值與觸摸點(diǎn)到偏置邊緣的距離成正比。觸摸點(diǎn)與接地邊之間的電阻相當(dāng)于分壓器中下面的那個(gè)電阻。因此,在未偏置層上測(cè)得的電壓與觸摸點(diǎn)到接地邊之間的距離成正比。四線觸摸屏包含兩個(gè)阻性層。其中一層在屏幕的左右邊緣各有一條垂直總線,另一層在屏幕的底部和頂部各有一條水平總線,如圖 12.5 所示。為了在 X 軸方向進(jìn)行測(cè)量,將左側(cè)總線偏置為 0V,右側(cè)總線偏置為 VREF。將頂部或底部總線連接到 ADC,當(dāng)頂層和底層相接觸時(shí)即可作一次測(cè)量。為了在 Y 軸方

23、向進(jìn)量,將頂部總線偏置為 VREF,底部總線偏置為 0V。將 ADC 輸入端接左側(cè)總線或右側(cè)總線,當(dāng)頂層與底層相接觸時(shí)即可對(duì)電壓進(jìn)量。學(xué)院華清遠(yuǎn)見旗下品牌:觸摸屏的驅(qū)動(dòng)驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例Linux圖 12.4 電阻觸摸屏分壓圖 12.5 四線電阻式觸摸屏S3C2410 接 4 線電阻式觸摸屏的電路原理如圖 12.6 所示。S3C2410 提供了 nYMON、YMON、nXPON 和 XMON 直接作為觸摸屏的信號(hào),它通過連接 FDC6321 場(chǎng)效應(yīng)管觸摸屏驅(qū)動(dòng)器觸摸屏。輸入信號(hào)在經(jīng)過阻容式低通濾器濾除坐標(biāo)信號(hào)噪聲后被接入 S3C2410 內(nèi)集成的 ADC(模

24、數(shù)轉(zhuǎn)換器)的模擬信號(hào)輸入通道 AIN5、AIN7。學(xué)院華清遠(yuǎn)見旗下品牌:Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例圖 12.6 S3C2410 連接 4 線電阻式觸摸屏S3C2410 內(nèi)置了一個(gè) 8 信道的 10 位 ADC,該 ADC 能以 500KS/S 的采樣速率將外部的模擬信號(hào)轉(zhuǎn)換為 10 位分辨率的數(shù)字量。因此,ADC 能與觸摸屏作,完成對(duì)觸摸屏絕對(duì)地址的測(cè)量。S3C2410 的 ADC 和觸摸屏接口可工作于 5 種模式,分別如下。1普通轉(zhuǎn)換模式(Normal Converson Mode)普通轉(zhuǎn)換模式(AUTO_PST = 0,XY_PST = 0)用來進(jìn)行一

25、般的 ADC 轉(zhuǎn)換,例如通過 ADC 測(cè)量電池電壓等。器協(xié)同工學(xué)院華清遠(yuǎn)見旗下品牌:Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例2X/Y 位置轉(zhuǎn)換模式(Separate X/Y Position Conversion Mode)X/Y 軸坐標(biāo)轉(zhuǎn)換模式其實(shí)包含了 X 軸模式和 Y 軸模式。為獲得 X、Y 坐標(biāo),需首先進(jìn)行 X 軸的坐標(biāo)轉(zhuǎn)換(AUTO_PST = 0,XY_PST = 1),X 軸的轉(zhuǎn)換資料會(huì)寫到ADCDAT0 寄存器的 XPDAT 中,等待轉(zhuǎn)換完成后,觸摸屏器會(huì)產(chǎn)生 INT_ADC 中斷。然后,進(jìn)行 Y 軸的坐標(biāo)轉(zhuǎn)換(AUTO_PST = 0,XY_PST =

26、 2),Y 軸的轉(zhuǎn)換資料會(huì)寫到 ADCDAT1 寄存器的 YPDAT 中,等待轉(zhuǎn)換完成后,觸摸屏INT_ADC 中斷。3自動(dòng)(連續(xù))X/Y 位置轉(zhuǎn)換模式(Auto X/Y Position Conversion Mode)自動(dòng)(連續(xù))X/Y 位置轉(zhuǎn)換模式(AUTO_PST = 1,XY_PST = 0)運(yùn)行方式是觸摸器也會(huì)產(chǎn)生屏自動(dòng)轉(zhuǎn)換 X 位置和 Y 位置。觸摸屏器在 ADCDAT0 的 XPDATA 位寫入 X測(cè)定數(shù)據(jù),在 ADCDAT1 的 YPADATA 位寫入 Y 測(cè)定數(shù)據(jù)。自動(dòng)(連續(xù))位置轉(zhuǎn)換后, 觸摸屏器產(chǎn)生 INT_ADC 中斷。4等待中斷模式(Wait for Interru

27、pt Mode)當(dāng)觸摸屏器等待中斷模式時(shí),它等待觸摸屏觸點(diǎn)信號(hào)的到來。當(dāng)觸點(diǎn)信號(hào)到來時(shí),器產(chǎn)生 INT_TC 中斷信號(hào)。然后,X 位置和 Y 位置能被適當(dāng)?shù)剞D(zhuǎn)換模式(獨(dú)立 X/Y 位置轉(zhuǎn)換模式或自動(dòng) X/Y 位置轉(zhuǎn)換模式)5待機(jī)模式(Standby Mode)當(dāng) ADCCON 寄存器的 STDBM 位置 1 時(shí),待機(jī)模式被激活。在這種模式下,A/D到。轉(zhuǎn)換動(dòng)作被換的數(shù)據(jù)。,ADCDAT0 的 XPDATA 位和 ADXDATA1 的 YPDAT 保留以前被轉(zhuǎn)12.2.2觸摸屏觸摸屏驅(qū)動(dòng)中數(shù)據(jù)結(jié)構(gòu)結(jié)構(gòu)體的成員與按鍵結(jié)構(gòu)體的成員類似,也包含一個(gè)緩沖區(qū),同時(shí)自旋鎖、等待隊(duì)列和 fasync_stru

28、ct 指針,如代碼12.12 所示。代碼12.12 觸摸屏結(jié)構(gòu)體觸摸屏結(jié)構(gòu)體中包含的 TS_RET 值的類型定義如代碼12.13 所示,包含 X、Y坐標(biāo)和狀態(tài)(PEN_DOWN、PEN_UP)等信息,這個(gè)信息會(huì)在用戶制到用戶空間。觸摸信息代碼12.13 TS_RET 結(jié)構(gòu)體學(xué)院華清遠(yuǎn)見旗下品牌:1 typedef struct1 typedef struct 2 3 unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */4 TS_RET bufMAX_TS_BUF; /* 緩沖區(qū) */5 unsigned int head, tai

29、l; /* 緩沖區(qū)頭和尾 */6 wait_queue_head_t wq; /*等待隊(duì)列*/7 spinlock_t lock;8 #ifdef USE_ASYNC9 struct fasync_struct *aq;10 #endif11 struct cdev cdev;12 TS_DEV;Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例在觸摸屏驅(qū)動(dòng)中,將實(shí)現(xiàn) open()、release()、read()、fasync()和 poll()函數(shù),因此,其文件操作結(jié)構(gòu)體定義如代碼12.14 所示。代碼12.14 觸摸屏驅(qū)動(dòng)文件操作結(jié)構(gòu)體12.2.3觸摸屏驅(qū)動(dòng)中的硬件代碼12

30、.15 中的一組宏用于觸摸屏和 ADC 進(jìn)入不同的工作模式,如等待中斷、X/Y 位置轉(zhuǎn)換等。代碼12.15觸摸屏和 ADC 硬件學(xué)院華清遠(yuǎn)見旗下品牌:1 #define wait_down_int() ADCTSC = DOWN_INT | XP_PULL_UP_EN |2 XP_AIN | XM_HIZ | YP_AIN | YM_GND | 3 XP_PST(WAIT_INT_MODE); 4 #define wait_up_int() ADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN|5 XM_HIZ |YP_AIN | YM_GND | XP_PST(W

31、AIT_INT_MODE); 6 #define mode_x_axis() ADCTSC = XP_EXTVLT | XM_GND | YP_AIN 7 | YM_HIZ |XP_PULL_UP_DIS | XP_PST(X_AXIS_MODE); 8 #define mode_x_axis_n() ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | 9 YM_HIZ |XP_PULL_UP_DIS | XP_PST(NOP_MODE); 10 #define mode_y_axis() ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT 11

32、 | YM_GND |XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE); 12 #define start_adc_x() ADCCON = PRESCALE_EN | PRSCVL(49) | 13 ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | 14 ADC_NORMAL_MODE; 15 ADCDAT0; 16 #define start_adc_y() ADCCON = PRESCALE_EN | PRSCVL(49) | 17 ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | 18 ADC_

33、NORMAL_MODE; 19 ADCDAT1; 20 #define disable_ts_adc() ADCCON &= (ADCCON_READ_START); 1 static struct file_operations s3c2410_fops = 2 3 owner: THIS_MODULE,4 open: s3c2410_ts_open, /打開5 read: s3c2410_ts_read, /讀坐標(biāo)6 release:7 s3c2410_ts_release,8 #ifdef USE_ASYNC9 fasync: s3c2410_ts_fasync, / fasyn

34、c()函數(shù)10 #endif11 poll: s3c2410_ts_poll,/輪詢12 ;2 3 unsigned short pressure;/PEN_DOWN、PEN_UP4 unsigned short x;/x 坐標(biāo)5 unsigned short y;/y 坐標(biāo)6 unsigned short pad;7 TS_RET;Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例12.2.4在觸摸屏設(shè)置觸摸屏12.16 所示。觸摸屏驅(qū)動(dòng)模塊加載和卸載函數(shù)驅(qū)動(dòng)的模塊加載函數(shù)中,要完成申請(qǐng)?zhí)?、添?cdev、申請(qǐng)中斷、引腳(YPON、YMON、XPON、XMON)等多項(xiàng)工作,如代

35、碼代碼12.16觸摸屏驅(qū)動(dòng)的模塊加載函數(shù)在觸摸屏等工作,如代碼驅(qū)動(dòng)的模塊卸載函數(shù)中,要完成12.17 所示。號(hào)、刪除 cdev、中斷代碼12.17 觸摸屏驅(qū)動(dòng)模塊卸載函數(shù)12.2.5觸摸屏驅(qū)動(dòng)中斷、定時(shí)器處理程序由 12.2.1 小節(jié)對(duì)觸摸屏和 ADC 模式的分析,可知觸摸屏驅(qū)動(dòng)中會(huì)產(chǎn)生兩類中斷, 一類是觸點(diǎn)中斷(INT-TC),一類是 X/Y 位置轉(zhuǎn)換中斷(INT-ADC)。在前一類中斷發(fā)生后,若之前處于 PEN_UP 狀態(tài),則應(yīng)該啟動(dòng) X/Y 位置轉(zhuǎn)換。另外,將抬起中斷也放學(xué)院華清遠(yuǎn)見旗下品牌:1 static void exit s3c2410_ts_exit(void) 2 3 ./號(hào)

36、,刪除 cdev4 free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);5 free_irq(IRQ_TC, s3c2410_isr_tc); 6 1 static int init s3c2410_ts_init(void) 2 3 int ret;4 tsEvent = tsEvent_dummy;5 ./申請(qǐng)?zhí)?,添?cdev 67 /* 設(shè)置 XP、YM、YP 和YM 對(duì)應(yīng)引腳 */8 set_gpio_ctrl(GPIO_YPON);9 set_gpio_ctrl(GPIO_YMON);10 set_gpio_ctrl(GPIO_XPON);11 set_

37、gpio_ctrl(GPIO_XMON); 1213 /* 使能觸摸屏中斷 */14 ret = request_irq(IRQ_ADC_DONE, s3c2410_isr_adc,15 SA_INTERRUPT, DEVICE_NAME,s3c2410_isr_adc);16 if (ret)17 goto adc_failed;18 ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT,19 DEVICE_NAME,s3c2410_isr_tc);20 if (ret)21 goto tc_failed; 2223 /*置于等待觸點(diǎn)中

38、斷模式*/24 wait_down_int(); 2526 printk(DEVICE_NAME " initializedn");2728 return 0;29 tc_failed:30 free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);31 adc_failed:32 return ret; 33 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例在 INT-TC 處理12.18 所示。,它會(huì)調(diào)用 tsEvent()完成等待隊(duì)列和信號(hào)的,如代碼代碼12.18觸摸屏驅(qū)動(dòng)的觸點(diǎn)/抬起中斷處理程序當(dāng) X/Y 位置轉(zhuǎn)換中斷發(fā)生后,應(yīng)

39、12.19 所示。X、Y 的坐標(biāo)值,填入緩沖區(qū),如代碼代碼12.19 觸摸屏驅(qū)動(dòng) X/Y 位置轉(zhuǎn)換中斷處理程序上述調(diào)用的 s3c2410_get_XY()用于獲得 X、Y 坐標(biāo),它使用代碼12.15的硬件操作宏實(shí)現(xiàn),如代碼12.20 所示。代碼12.20 觸摸屏驅(qū)動(dòng)中獲得 X、Y 坐標(biāo)學(xué)院華清遠(yuǎn)見旗下品牌:1 static inline void s3c2410_get_XY(void) 2 1 static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs*reg)2 3 spin_lock_irq(&(tsdev.

40、lock);4 if (tsdev.penStatus = PEN_UP)5s3c2410_get_XY(); /坐標(biāo)6 #ifdef HOOK_FOR_DRAG7 else8s3c2410_get_XY();9 #endif10 spin_unlock_irq(&(tsdev.lock); 11 1 static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs*reg)2 3 spin_lock_irq(&(tsdev.lock);4 if (tsdev.penStatus = PEN_UP) 56start

41、_ts_adc(); /開始 X/Y 位置轉(zhuǎn)換78else910 tsdev.penStatus = PEN_UP;11 DPRINTK("PEN UP: x: %08d, y: %08dn", x, y);12 wait_down_int();/置于等待觸點(diǎn)中斷模式13 tsEvent();14 15 spin_unlock_irq(&(tsdev.lock); 16 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例代碼12.18、12.20 中調(diào)用的 tsEvent 最終為 tsEvent_raw(),這個(gè)函數(shù)很關(guān)鍵,當(dāng)處于 PEN_DOWN 狀

42、態(tài)時(shí)調(diào)用該函數(shù),它會(huì)完成緩沖區(qū)的填充、等待隊(duì)列的喚醒以;否則(處于 PEN_UP 狀態(tài)),將緩沖區(qū)頭清 0,也喚醒等待及異步通知信號(hào)的隊(duì)列并信號(hào),如代碼12.21 所示。代碼12.21觸摸屏驅(qū)動(dòng)的 tsEvent_raw()函數(shù)學(xué)院華清遠(yuǎn)見旗下品牌:1 static void tsEvent_raw(void) 2 3if (tsdev.penStatus = PEN_DOWN)45 /*填充緩沖區(qū)*/6 BUF_HEAD.x = x;7 BUF_HEAD.y = y;8 BUF_HEAD.pressure = PEN_DOWN; 910 #ifdef HOOK_FOR_DRAG11 ts_t

43、imer.expires = jiffies + TS_TIMER_DELAY;12 add_timer(&ts_timer);/啟動(dòng)定時(shí)器13 #endif14 15 else16 17 #ifdef HOOK_FOR_DRAG18 del_timer(&ts_timer);19 #endif 2021 /*填充緩沖區(qū)*/22 BUF_HEAD.x = 0;23 BUF_HEAD.y = 0;24 BUF_HEAD.pressure = PEN_UP; 25 2627 tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);28 wake_up

44、_interruptible(&(tsdev.wq); /喚醒等待隊(duì)列293if (adc_state = 0) 45 adc_state = 1;6 disable_ts_adc(); /INT-ADC7 y = (ADCDAT0 &0x3ff); /坐標(biāo)值8 mode_y_axis();9 start_adc_y(); /開始 y 位置轉(zhuǎn)換10 11 else if (adc_state = 1) 12 13 adc_state = 0;14 disable_ts_adc(); /INT-ADC15 x = (ADCDAT1 &0x3ff); /坐標(biāo)值16 tsde

45、v.penStatus = PEN_DOWN;17 DPRINTK("PEN DOWN: x: %08d, y: %08dn", x, y);18 wait_up_int(); /置于等待抬起中斷模式19 tsEvent();20 21 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例在包含了對(duì)拖動(dòng)軌跡支持的情況下,定時(shí)器會(huì)被啟用,周期為 10ms,在每次定時(shí)器處理函數(shù)被所示。時(shí),調(diào)用 start_ts_adc()開始 X/Y 位置轉(zhuǎn)換過程,如代碼12.22學(xué)院華清遠(yuǎn)見旗下品牌:30 #ifdef USE_ASYNC31 if (tsdev.aq)32 ki

46、ll_fasync(&(tsdev.aq), SIGIO, POLL_IN);/異步通知33 #endif34 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例12.22 觸摸屏驅(qū)動(dòng)的定時(shí)器處理函數(shù)代碼12.2.6在觸摸屏觸摸屏驅(qū)動(dòng)的打開、函數(shù)驅(qū)動(dòng)的打開函數(shù)中,應(yīng)初始化緩沖區(qū)、penStatus 和定期器、等待隊(duì)列及 tsEvent 時(shí)間處理函數(shù)指針,如代碼12.23 所示。12.23 觸摸屏代碼驅(qū)動(dòng)的打開函數(shù)觸摸屏可,如代碼驅(qū)動(dòng)的函數(shù)非常簡(jiǎn)單,刪除為用于拖動(dòng)軌跡所使用的定時(shí)器即12.24 所示。12.24 觸摸屏代碼驅(qū)動(dòng)的函數(shù)12.2.7觸摸屏?xí)r,直接觸摸屏驅(qū)動(dòng)的讀函

47、數(shù)驅(qū)動(dòng)的讀函數(shù)實(shí)現(xiàn)緩沖區(qū)中信息向用戶空間的,當(dāng)緩沖區(qū)有內(nèi)容;否則,如果用戶阻塞觸摸屏,則進(jìn)程在等待隊(duì)列上睡眠,否則,立即返回-EAGAIN,如代碼12.25 所示。學(xué)院華清遠(yuǎn)見旗下品牌:1 static int s3c2410_ts_release(struct inode *inode, struct file *filp) 2 3 #ifdef HOOK_FOR_DRAG4 del_timer(&ts_timer);/刪除定時(shí)器5 #endif6 return 0;7 1 static int s3c2410_ts_open(struct inode *inode, struct

48、file *filp) 2 3 tsdev.head = tsdev.tail = 0;4 tsdev.penStatus = PEN_UP;/初始化觸摸屏狀態(tài)為 PEN_UP5 #ifdef HOOK_FOR_DRAG /如果定義了拖動(dòng)鉤子函數(shù)6 init_timer(&ts_timer);/初始化定時(shí)器7 ts_timer.function = ts_timer_handler;8 #endif9 tsEvent = tsEvent_raw;10 init_waitqueue_head(&(tsdev.wq);/初始化等待隊(duì)列1112 return 0;13 1 #ifde

49、f HOOK_FOR_DRAG2 static void ts_timer_handler(unsigned long data) 34 spin_lock_irq(&(tsdev.lock);5 if (tsdev.penStatus = PEN_DOWN) 67start_ts_adc(); /開始 X/Y 位置轉(zhuǎn)換89spin_unlock_irq(&(tsdev.lock); 10 11 #endifLinux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例12.25代碼觸摸屏驅(qū)動(dòng)的讀函數(shù)12.2.8在觸摸屏觸摸屏驅(qū)動(dòng)的輪詢與異步通知驅(qū)動(dòng)中,通過 s3c2410_

50、ts_poll()函數(shù)實(shí)現(xiàn)了輪詢接口,這個(gè)函數(shù)的實(shí)現(xiàn)非常簡(jiǎn)單。它將等待隊(duì)列添加到 poll_table,當(dāng)緩沖區(qū)有數(shù)據(jù)時(shí),返回可標(biāo)志,否則返回 0,如代碼12.26 所示。代碼12.26 觸摸屏驅(qū)動(dòng)的 poll()函數(shù)而為了實(shí)現(xiàn)觸摸屏驅(qū)動(dòng)對(duì)應(yīng)用程序的異步通知,驅(qū)動(dòng)中要實(shí)現(xiàn)s3c2410_ts_fasync()函數(shù),這個(gè)函數(shù)與第 9 章給出的模板完全一樣,如代碼所示。12.27代碼12.27 觸摸屏驅(qū)動(dòng)的 fasync()函數(shù)學(xué)院華清遠(yuǎn)見旗下品牌:1 #ifdef USE_ASYNC2 static int s3c2410_ts_fasync(int fd, struct file *filp,

51、 int mode)1 static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)2 3 poll_wait(filp, &(tsdev.wq), wait);/添加等待隊(duì)列到 poll_table4 return (tsdev.head = tsdev.tail) ? 0 : (POLLIN | POLLRDNORM); 5 1 static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t c

52、ount,2 loff_t *ppos) 3 4TS_RET ts_ret;56 retry:7 if (tsdev.head != tsdev.tail) /緩沖區(qū)有信息89 int count;10 count = tsRead(&ts_ret);11 if (count)12 copy_to_user(buffer, (char*) &ts_ret, count);/到用戶空間13 return count;14 15 else16 17 if (filp->f_flags &O_NONBLOCK)/非阻塞讀18 return - EAGAIN;19 interruptible_sleep_on(&(tsdev.wq); /在等待隊(duì)列上睡眠20 if (signal_pending(current)21 return - ERESTARTSYS;22 goto retry;23 2425 return sizeof(TS_RET); 26 Linux驅(qū)動(dòng)開發(fā)詳解第 12 章、Linux 字符驅(qū)動(dòng)綜合實(shí)例學(xué)院華清遠(yuǎn)見旗下品牌:3 4return f

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論