天天看点

触摸屏驱动设计----输入子系统模型

输入子系统模型 介绍

对于键盘、鼠标、触摸屏等输入设备的驱动程序来说,用户程序所调用的操作函数集基本上相同,这些驱动的主要区别在于各自的中断处理函数对硬件的访问不同,因此为了简化程序的设计,将所有输入设备的驱动简化,提出一些共性的东西形成输入子系统,让不同的驱动程序实现不同的硬件处理程序即可。

输入子系统如下图所示:

触摸屏驱动设计----输入子系统模型

输入子系统由设备驱动层(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

继续阅读