<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          關(guān) 閉

          新聞中心

          EEPW首頁(yè) > 工控自動(dòng)化 > 設(shè)計(jì)應(yīng)用 > 基于Linux內(nèi)核的鍵盤(pán)模擬實(shí)現(xiàn)

          基于Linux內(nèi)核的鍵盤(pán)模擬實(shí)現(xiàn)

          作者: 時(shí)間:2012-08-17 來(lái)源:網(wǎng)絡(luò) 收藏

          1 引言

          本文引用地址:http://www.ex-cimer.com/article/202221.htm

          當(dāng)前,由于資源完全公開(kāi),使得的發(fā)展日益廣泛快速?;?a class="contentlabel" href="http://www.ex-cimer.com/news/listbylabel/label/Linux">Linux的各種應(yīng)用已逐漸深入日常生活的方方面面,尤其是在嵌入式領(lǐng)域,由于可裁減定制,因此可隨意地根據(jù)用戶需求進(jìn)行整個(gè)系統(tǒng)的定制與重構(gòu)。其中,我們可以通過(guò)對(duì)各種標(biāo)準(zhǔn)外部設(shè)備的驅(qū)動(dòng)進(jìn)行改造,從而實(shí)現(xiàn)用戶對(duì)標(biāo)準(zhǔn)設(shè)備的特定需求,例如可以通過(guò)對(duì)來(lái)實(shí)現(xiàn)操作的自動(dòng)化,從而可以避免重復(fù)的操作。

          2 Linux支持的外部調(diào)用接口

          由于Linux作為系統(tǒng)最深層次的核心,因此外部的開(kāi)發(fā)人員并不能直接對(duì)內(nèi)核進(jìn)行操作。然而在一些應(yīng)用程序的開(kāi)發(fā)過(guò)程中,又不得不使用內(nèi)核的某些功能,因此就提供了一些外部接口供開(kāi)發(fā)人員直接與底層內(nèi)核打交道。

          2.1 中斷

          在Linux 下,硬件中斷叫做IRQ(Interrupt Requests)。有兩種IRQ,短類型和長(zhǎng)類型。短IRQ需要很短的時(shí)間,在此期間機(jī)器的其他部分被鎖定,而且沒(méi)有其他中斷被處理。一個(gè)長(zhǎng)IRQ需要較長(zhǎng)的時(shí)間,在此期間可能發(fā)生其他中斷(但不是發(fā)自同一個(gè)設(shè)備)。如果可能的話,最好把一個(gè)中段聲明為長(zhǎng)類型。如果CPU接到一個(gè)中斷,它就會(huì)停止一切工作(除非它正在處理一個(gè)更重要的中斷,在這種情況下要等到更重要的中斷處理結(jié)束后才會(huì)處理這個(gè)中斷),把相關(guān)的參數(shù)存儲(chǔ)到棧里,然后調(diào)用中斷處理程序。這意味著在中斷處理程序本身中有些事情是不允許的,因?yàn)檫@時(shí)系統(tǒng)處在一個(gè)未知狀態(tài)。解決這個(gè)問(wèn)題的方法是讓中斷處理程序做需要馬上做的事,通常是從硬件讀取信息或給硬件發(fā)送信息,然后把對(duì)新信息的處理調(diào)度到以后去做。

          實(shí)現(xiàn)的方法是在接到相關(guān)的IRQ(在Intel平臺(tái)上有16個(gè)IRQ)時(shí)調(diào)用中斷處理程序。這個(gè)函數(shù)接到IRQ號(hào)碼、函數(shù)名、標(biāo)志、一個(gè)/proc/interrupts的名字和傳給中斷處理程序的一個(gè)參數(shù)。標(biāo)志中可以包括 SA_SHIRQ來(lái)表明你希望和其他處理程序共享此IRQ(通常很多設(shè)備公用一個(gè)IRQ),或者一個(gè)SA_INTERRUPT表明這是一個(gè)緊急中斷。這個(gè)函數(shù)僅在此IRQ沒(méi)有其他處理程序或需要共享所有處理程序時(shí)才會(huì)成功運(yùn)行。

          2.2 系統(tǒng)調(diào)用

          系統(tǒng)調(diào)用發(fā)生在用戶進(jìn)程,通過(guò)一些特殊的函數(shù)來(lái)請(qǐng)求內(nèi)核提供服務(wù)。這時(shí),用戶進(jìn)程被掛起,內(nèi)核驗(yàn)證用戶請(qǐng)求,嘗試執(zhí)行并把結(jié)果反饋給用戶進(jìn)程,接著用戶進(jìn)程重新啟動(dòng)。一般當(dāng)前系統(tǒng)的系統(tǒng)調(diào)用作為一張表sys_call_table進(jìn)行定義的,是由指向?qū)崿F(xiàn)各種系統(tǒng)調(diào)用的內(nèi)核函數(shù)的函數(shù)指針組成的表。具體參數(shù)參見(jiàn)Linux內(nèi)核源代碼arch/i386/kernel/entry.S文件中:

          ENTRY(sys_call_table)

          l long SYMBOL_NAME(sys_ni_syscall)

          /* 0 - old setup() system call*/

          l long SYMBOL_NAME(sys_exit)

          l long SYMBOL_NAME(sys_ni_syscall)

          /* streams2 */

          l long SYMBOL_NAME(sys_vfork)

          /* 190 */

          2.3 鉤子函數(shù)

          鉤子(HOOK)是Linux系統(tǒng)中非常重要的系統(tǒng)接口,用它可以截獲并處理送給其他應(yīng)用程序的消息,來(lái)完成普通應(yīng)用程序難以實(shí)現(xiàn)的功能。鉤子可以監(jiān)視系統(tǒng)或進(jìn)程中的各種事件消息,截獲發(fā)往目標(biāo)的消息并進(jìn)行處理。這樣就可以在系統(tǒng)中安裝自定義的鉤子,監(jiān)視系統(tǒng)中特定事件的發(fā)生,完成特定的功能,比如截獲、鼠標(biāo)的輸入,屏幕取詞,日志監(jiān)視等等??梢?jiàn),利用鉤子可以實(shí)現(xiàn)許多特殊而有用的功能。

          3 鍵盤(pán)工作機(jī)理

          CPU對(duì)外部設(shè)備的管理是通過(guò)中斷程序進(jìn)行的,鍵盤(pán)也是一種外部設(shè)備,因此,CPU對(duì)鍵盤(pán)的管理也是通過(guò)中斷進(jìn)行的。當(dāng)你擊打鍵盤(pán)的時(shí)候,鍵盤(pán)控制器會(huì)向CPU提出中斷申請(qǐng),CPU響應(yīng)此中斷進(jìn)行處理,這就完成了一次很簡(jiǎn)單與人之間通過(guò)鍵盤(pán)進(jìn)行的交互。

          首先,當(dāng)輸入一個(gè)鍵盤(pán)值的時(shí)候,鍵盤(pán)將會(huì)發(fā)送相應(yīng)的scancodes給鍵盤(pán)驅(qū)動(dòng)。一個(gè)獨(dú)立的擊鍵可以產(chǎn)生一個(gè)六個(gè)scancodes的隊(duì)列。鍵盤(pán)驅(qū)動(dòng)中的 handle_ scancode()函數(shù)解析scancodes流并通過(guò)kdb_translate()函數(shù)里的轉(zhuǎn)換表(translation-table)將擊鍵事件和鍵的釋放事件(key release events)轉(zhuǎn)換成連續(xù)的keycode。例如,'a'的keycode是30。擊鍵'a'的時(shí)候便會(huì)產(chǎn)生keycode 30。釋放a鍵的時(shí)候會(huì)產(chǎn)生keycode 158(128+30)。

          然后,這些keycode通過(guò)對(duì)keymap的查詢被轉(zhuǎn)換成相應(yīng)key符號(hào)。獲得的字符被送入raw tty隊(duì)列—tty_flip_buffer。receive_buf()函數(shù)周期性的從tty_flip_buffer中獲得字符,然后把這些字符送入 tty read隊(duì)列。

          當(dāng)用戶進(jìn)程需要得到用戶的輸入的時(shí)候,它會(huì)在進(jìn)程的標(biāo)準(zhǔn)輸入(stdin)調(diào)用read()函數(shù)。sys_read()函數(shù)調(diào)用定義在相應(yīng)的tty設(shè)備(如/dev/tty0)的file_operations結(jié)構(gòu)中指向tty_read的read()函數(shù)來(lái)讀取字符并且返回給用戶進(jìn)程。

          4 鍵盤(pán)的實(shí)現(xiàn)

          通常情況下,對(duì)鍵盤(pán)的實(shí)現(xiàn)一般是通過(guò)寫(xiě)一個(gè)自己的鍵盤(pán)中斷句柄來(lái)實(shí)現(xiàn),但這種方法容易導(dǎo)致系統(tǒng)崩潰。因此,在這種方法的基礎(chǔ)上可以利用勾子函數(shù)來(lái)實(shí)現(xiàn)。

          如附圖所示,這里主要用到的勾子函數(shù)包括handle_ scancode(),put_queue(),receive_buf(),tty_read()和sys_read()等函數(shù)。

          4.1 handle_scancode函數(shù)

          handle_scancode函數(shù)是鍵盤(pán)驅(qū)動(dòng)程序中的一個(gè)入口函數(shù)(參見(jiàn)文件/usr/src/linux/drives/char/keyboard.c):

          void handle_scancode(unsigned char scancode, int down);

          這里通過(guò)替換原始的handle_scancode()函數(shù)來(lái)實(shí)現(xiàn)紀(jì)錄所有的scancode。即將原始的值保存,把新的值注冊(cè)進(jìn)去,從而實(shí)現(xiàn)所需要的功能,最后再調(diào)用回到原始值的情況下。當(dāng)此新的功能函數(shù)完成后,我們就可以記錄下鍵盤(pán)上的正確的擊鍵行為了(其中可以包括一些特殊的key,如ctrl, alt,shift,print screen等等)。

          4.2 put_queue函數(shù)

          handle_scancode()函數(shù)會(huì)調(diào)用put_queue函數(shù),用來(lái)將字符放入tty_queue。

          put_queue函數(shù)在內(nèi)核中定義如下:

          void put_queue(int ch)

          {

          wake_up(keypress_wait);

          if (tty) {

          tty_insert_flip_char(tty, ch, 0);

          con_schedule_flip(tty); }}

          4.3 receive_buf函數(shù)

          linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)

          DIY機(jī)械鍵盤(pán)相關(guān)社區(qū):機(jī)械鍵盤(pán)DIY


          linux相關(guān)文章:linux教程



          上一頁(yè) 1 2 下一頁(yè)

          關(guān)鍵詞: Linux 內(nèi)核 鍵盤(pán) 模擬

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();