天天看點

Linux驅動之input輸入子系統

input輸入子系統在實際項目中用的也比較多,按鍵,觸摸屏,滑鼠,鍵盤等,用來實作核心層和應用層資料之間的傳遞,這裡得說明不隻有input,還有copy_to_user等,利用input的好處是我們用自己上傳資料到應用程式, 我們直接上報這個事件發生了,input自帶的機制會實作上傳的功能。還有很多開源的工具也是基于input輸入來制作的,像tslib觸摸檢測程式和提取資料。

tips:不要啟動qt程式,否則會出錯,用cat /dev/tty1 來測試。

驅動程式:

/* 參考drivers\input\keyboard\gpio_keys.c */

#include <linux/module.h>

#include <linux/version.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

#include <linux/sched.h>

#include <linux/pm.h>

#include <linux/sysctl.h>

#include <linux/proc_fs.h>

#include <linux/delay.h>

#include <linux/platform_device.h>

#include <linux/input.h>

#include <asm/gpio.h>

#include <asm/io.h>

#include <linux/kernel.h>/*核心有關的*/

#include <linux/device.h>

#include <linux/miscdevice.h>

#include <asm/uaccess.h>  //copy_to_user

#include <mach/regs-gpio.h>/*寄存器設定*/

#include <mach/hardware.h>//s3c2410_gpio_getpin等的定義

#include <mach/irqs.h> //irq_eint0等的定義

#include <asm/system.h>

struct pin_desc{     /* 定義一個結構體類型 */

int irq;

char *name;

unsigned int pin;

unsigned int key_val;

};

struct pin_desc pins_desc[4] = {      /* 定義這種類型的結構體數組并指派 */

{irq_eint0,  "s0", s3c2410_gpf0,   key_l},

{irq_eint2,  "s2", s3c2410_gpf2,   key_s},

{irq_eint3,  "s3", s3c2410_gpf3,   key_enter},

{irq_eint4,  "s4", s3c2410_gpf4,   key_leftshift},

static struct input_dev *buttons_dev;     /* 定義input_dev類型的結構體指針 */

static struct pin_desc *irq_pd;

static struct timer_list buttons_timer;

static irqreturn_t buttons_irq(int irq, void *dev_id)   /* 定時器,這裡用來消除抖動 */

{

/* 10ms後啟動定時器 */

irq_pd = (struct pin_desc *)dev_id;

mod_timer(&buttons_timer, jiffies+hz/100);

return irq_retval(irq_handled);

}

static void buttons_timer_function(unsigned long data)

struct pin_desc * pindesc = irq_pd;

unsigned int pinval;

if (!pindesc)

return;

pinval = s3c2410_gpio_getpin(pindesc->pin);

if (pinval)

/* 松開 : 最後一個參數: 0-松開, 1-按下 */

input_event(buttons_dev, ev_key, pindesc->key_val, 0);

input_sync(buttons_dev);

else

/* 按下 */

input_event(buttons_dev, ev_key, pindesc->key_val, 1);

static int buttons_init(void)   /* 初始化函數,硬體初始化,注冊中斷,配置設定記憶體 */

int i;

/* 1. 配置設定一個input_dev結構體 */

buttons_dev = input_allocate_device();  /*  */

/* 2. 設定 */

/* 2.1 能産生哪類事件 */

set_bit(ev_key, buttons_dev->evbit);

//set_bit(ev_rep, buttons_dev->evbit);

/* 2.2 能産生這類操作裡的哪些事件: l,s,enter,leftshit */

set_bit(key_l, buttons_dev->keybit);

set_bit(key_s, buttons_dev->keybit);

set_bit(key_enter, buttons_dev->keybit);

set_bit(key_leftshift, buttons_dev->keybit);

/* 3. 注冊 */

input_register_device(buttons_dev);

/* 4. 硬體相關的操作 */

init_timer(&buttons_timer);

buttons_timer.function = buttons_timer_function;

add_timer(&buttons_timer);

for (i = 0; i < 4; i++)

request_irq(pins_desc[i].irq, buttons_irq, irqf_trigger_falling|irqf_trigger_rising, pins_desc[i].name, &pins_desc[i]);

return 0;

static void buttons_exit(void)   /* 退出函數,取消中斷的注冊,釋放記憶體 */

free_irq(pins_desc[i].irq, &pins_desc[i]);

del_timer(&buttons_timer);

input_unregister_device(buttons_dev);   /* 取消注冊的結構體 */

input_free_device(buttons_dev);           /* 取消配置設定的結構體 */

module_init(buttons_init);

module_exit(buttons_exit);

module_license("gpl");

注冊input_dev或input_handler時,會兩兩比較左邊的input_dev和右邊的input_handler,

根據input_handler的id_table判斷這個input_handler能否支援這個input_dev,

如果能支援,則調用input_handler的connect函數建立"連接配接"

上面調用input上報事件最終都将調用到input_sync最終也将調用input_envent,該代碼還有一個問題,細心的朋友應該看到了,怎麼沒有看到休眠和喚醒之類的代碼呢?這些穩定的部分核心裡面已經自帶了,在input_event裡面來實作喚醒的,這些核心在穩定部分已經實作了,我們隻需讀到資料直接上報就行了,具體應用程式怎麼取讀是應用層的事情。

unsigned long evbit[nbits(ev_max)];   // 表示能産生哪類事件

unsigned long keybit[nbits(key_max)]; // 表示能産生哪些按鍵

unsigned long relbit[nbits(rel_max)]; // 表示能産生哪些相對位移事件, x,y,滾輪

unsigned long absbit[nbits(abs_max)]; // 表示能産生哪些絕對位移事件, x,y

#define ev_syn 0x00      /* 同步類事件 */

#define ev_key 0x01/* 按鍵類事件 */

#define ev_rel 0x02/* 相對位移類事件 */

#define ev_abs 0x03/* 絕對位移類事件 */

set_bit(ev_key, buttons_dev->evbit);                    /* 能産生按鍵類事件 */

set_bit(ev_rep, buttons_dev->evbit); /* 能産生重複類事件 */

set_bit(key_l, buttons_dev->keybit);            /*能産生(key_l這些事件*/

 /*能産生key_s這些事件*/

set_bit(key_enter, buttons_dev->keybit);     /*能産生key_enter這些事件*/

set_bit(key_leftshift, buttons_dev->keybit);    /*能産生key_leftshift這些事件*/

input_sync(buttons_dev);            /* 上報同步類事件 */

測試方法如下:

1. 

hexdump /dev/event1  (open(/dev/event1), read(), )

           秒        微秒    類  code    value

0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000

0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000

0000020 0bb2 0000 5815 000e 0001 0026 0000 0000

0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

2. 如果沒有啟動qt:

cat /dev/tty1

按:s2,s3,s4

就可以得到ls

或者:

exec 0</dev/tty1                 /* 把标準輸入檔案改為tty1,0代表标準輸入,1代表标準輸出,2代表标準錯誤 */

然後可以使用按鍵來輸入

繼續閱讀