天天看點

linux 2.6 輸入子系統 鍵盤驅動的實作

好久沒來了!寫點東西.關于linux 2.6下面的鍵盤驅動的實作.

    2.6核心采用"input sub system" 的概念.将輸入驅動分成三塊: driver,input core和Event handler. "一個輸入事件,如滑鼠移動,鍵盤按鍵按下,joystick的移動等等通過 Driver -> InputCore -> Eventhandler -> userspace 的順序到達使用者空間傳給應用程式。"

    關于輸入子系統詳細的文章有一個老兄寫了一篇:

    http://blog.csdn.net/colorant/archive/2007/04/12/1561837.aspx

    在這裡我膚淺得講一下如何實作一個驅動.todo

正文

2.6輸入子系統使得使用者空間可以通過字元裝置接口毫無遺漏的獲得原始的輸入消息。比如說有些智能滑鼠,除了坐标滾球,三鍵,滾輪之外還有其他的輸入裝置,,比如控制系統音量的按鈕.

如何注冊裝置

       int key,code;

       button_dev = input_allocate_device();

       init_input_dev(button_dev);

       set_bit(EV_KEY,button_dev->evbit);

       //@set_bit(EV_REP,button_dev->evbit);       //repeat

       for(key=0;key<16;key++)

              set_bit(keypad_keycode[key],button_dev->keybit);

       button_dev->name = PCA9554_DRV_NAME;

       button_dev->id.bustype = BUS_HOST;

       input_register_device(button_dev);

如上述代碼所示,首先配置設定一個輸入裝置,之後對其進行初始化,然後配置參數. “set_bit(EV_KEY,button_dev->evbit);”将該輸入裝置定義為鍵盤輸入,這樣input core在分發消息的時候會将其發送到keyboard event handler.

接着就是初始化鍵盤定義,這裡keybit是由若幹個long型變量組成的數組,我所用的kernel直至最大按鍵數目為0x1ff.

       for(key=0;key<16;key++)

              set_bit(keypad_keycode[key],button_dev->keybit);

我的開發闆上有16個按鍵,因為項目是播放器,是以我對其作了定義:

int keypad_keycode[] = {

              KEY_UP,  KEY_DOWN,     KEY_A,   KEY_B,              // 1 - 4

              KEY_LEFT, KEY_RIGHT,    KEY_C,   KEY_D,             // 5 - 8

              KEY_PLAYPAUSE,KEY_PLAY,KEY_NEXTSONG,KEY_VOLUMEUP,   // 9 - 12

              KEY_CANCEL,KEY_OK,KEY_PREVIOUSSONG,KEY_VOLUMEDOWN,  // 13 - 16

              KEY_UNKNOWN,

       };

鍵盤定義示意圖

在input.c的input_event函數中會對keybit進行判斷,确定某個按鍵對應的位是否被打開,否則不予上傳鍵值.

              case EV_KEY:

                     printk("haigang;:%s: code:%d,value=%d/n",__FUNCTION__,code,value);

                     if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value){

                            printk("haigang:%s: code too big/n",__FUNCTION__,code);

                            return;

                     }

                     if (value == 2)

                            break;

                     change_bit(code, dev->key);

                     if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {

                            dev->repeat_key = code;

                            mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));

                     }

                     break;

input_event部分代碼

如何傳送輸入鍵值比較簡單,隻需要使用   函數void input_event即可,該函數定義

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

在include/linux/input.h中對該函數作了封裝

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

{

       input_event(dev, EV_KEY, code, !!value);

}

這裡code是鍵值,value應該是鍵盤狀态,按下或者釋放(僅是猜測,有待考證)

我的驅動中的建值傳輸代碼,當鍵值是0x16時候,表示松開鍵盤事件

       unsigned char key;

       static unsigned char oldKey=0x16;

       key = pca9554_readKey();

       //@printk("KEY:%d/n",key);

       if(key!=0x16){

              input_report_key(button_dev,keypad_keycode[key],1);

              input_sync(button_dev);

       }else{

              input_report_key(button_dev,keypad_keycode[oldKey],0);

              input_sync(button_dev);

       }

       set_irq_type(IRQ_KEYPAD,IRQT_FALLING);

       s3c_gpio_cfgpin(S3C_GPF4,S3C_GPF4_EINT4);

       oldKey=key;

繼續閱讀