輸入子系統模型 介紹
對于鍵盤、滑鼠、觸摸屏等輸入裝置的驅動程式來說,使用者程式所調用的操作函數集基本上相同,這些驅動的主要差別在于各自的中斷處理函數對硬體的通路不同,是以為了簡化程式的設計,将所有輸入裝置的驅動簡化,提出一些共性的東西形成輸入子系統,讓不同的驅動程式實作不同的硬體處理程式即可。
輸入子系統如下圖所示:

輸入子系統由裝置驅動層(input device driver),核心層(input core)和事件驅動層(event driver)三部份組成。任何一次輸入事件,如滑鼠移動,按鍵按下,都需要通過:
InputDeviceDriver->InputCore->EventDrive
才能到達使用者空間的應用程式。
裝置驅動層:
将底層的硬體輸入轉化為統一事件型式,向輸入核心(InputCore)彙報。
輸入核心層:
為裝置驅動層提供輸入裝置注冊與操作接口,如:input_ register_ device;通知事件處理層對事件進行處理;
事件驅動層:
主要作用是和使用者空間互動,如提供read,open等裝置方法,建立裝置檔案等。
事件類型:
EV_ RST:Reset
EV_KEY:按鍵
EV_ REL:相對坐标
EV_ABS:絕對坐标
EV_ MSC:其它
EV_LED :LED
EV_ SND: 聲音
EV_ REP: Repeat
EV_ FF :力回報
當事件類型為EV_KEY時,還需指明按鍵類型:
BTN_ LEFT:滑鼠左鍵
BTN_ RIGHT:滑鼠右鍵
BTN_0:數字0鍵
BTN_1:數字1鍵
輸入型驅動模型圖:
代碼舉例:
按鍵輸入驅動設計(将前面的按鍵驅動進行改造):
驅動程式代碼舉例:
//初始化入口函數
static int button_init()
{
int ret;
/*配置設定輸入型裝置結構*/
button_dev = input_allocate_device();
/*申明所支援的事件類型*/
set_bit(EV_KEY,button_dev->evbit);
/*申明可能上報的鍵編号*/
set_bit(KEY_3,button_dev->keybit);
set_bit(KEY_4,button_dev->keybit);
/*注冊輸入型裝置*/
input_register_device(button_dev);
//注冊中斷處理程式
request_irq(IRQ_EINT0,key_int,IRQF_TRIGGER_FALLING,"key",(void *));
request_irq(IRQ_EINT2,key_int,IRQF_TRIGGER_FALLING,"key",(void *));
//按鍵初始化
key_hw_init();
//建立工作
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1, work1_func);
/* 初始化定時器 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
/* 向核心注冊一個定時器 */
add_timer(&buttons_timer);
/*初始化等待隊列*/
init_waitqueue_head(&key_q);
return ;
}
//定時器中斷函數
void buttons_timer_function(unsigned long data)
{
unsigned int key_val;
key_val = readw(gpio_data)&;
if (key_val == )
{
key_num = ;
//上報事件
input_report_key(button_dev,KEY_4,);
}
key_val = readw(gpio_data)&;
if (key_val == )
{
key_num = ;
//上報事件
input_report_key(button_dev,KEY_3,);
}
//告訴核心上報結束
input_sync(button_dev);
}
應用程式代碼舉例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
int main(void)
{
int buttons_fd;
int key_value,i=,count;
//對應的輸入裝置結構體
struct input_event ev_key;
buttons_fd = open("/dev/event1", O_RDWR);
if (buttons_fd < ) {
perror("open device buttons");
exit();
}
for (;;) {
//特别注意:這裡的讀取函數的參數格式是固定的,必須這麼寫
count = read(buttons_fd,&ev_key,sizeof(struct input_event));
for(i=; i<(int)count/sizeof(struct input_event); i++)
if(EV_KEY==ev_key.type)
printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code-,ev_key.value);
if(EV_SYN==ev_key.type)
printf("syn event\n\n");
}
close(buttons_fd);
return ;
}
觸摸屏驅動設計
初始化:
1、使能ADC時鐘
2、将實體位址轉化為虛拟位址
3、讓觸摸屏進入到等待中斷的模式
4、配置設定輸入裝置結構
5、設定可能上報的事件類型和按鍵類型
6、為TC和ADC中斷注冊處理函數
7、注冊輸入型裝置
按下處理:
1、判斷觸摸屏按下還是彈起,按下後進入TC中斷處理程式
2、啟動X與Y坐标的AD轉換,觸發ADC中斷
3、進行4次ADC轉換,擷取4次X與Y的值,考慮精度要求
4、計算4次坐标的平均值,并上報核心
源代碼位置:
linux-tq2440\drivers\input\touchscreen\tq2440_ts.c