linux驱动开发:input子系统二

来源:互联网 发布:linux piwik安装 编辑:程序博客网 时间:2024/06/14 03:14

输入子系统:linux内核中将所有输入设备归为一个类:input子系统。里面实现了几乎所有输入设备的公共操作接口,相当于内核给我们搭建了一个输入子系统的框架,我们用它的框架开发驱动,会变得非常简单。因为一些公共的函数内核已经帮我们实现好了,我们只需要实现不同输入设备间的差异部分即可。

上篇文章 记录了在输入子系统的框架下实现一个按键的上报功能。一个输入设备,上报一种按键事件。

那么一个输入设备,也是可以上报多种按键事件的。

因为上一章的框架已经搭建好,我们只需要注册其他的按键中断并上报按键事件即可。所以整个代码就变得非常简单。

当然,如果作为模块:在模块卸载时,需要逆序消除对内核的影响。简单的讲: 在你的init函数中 register一个设备,那么在你的exit函数中就应该 unregister这个设备.

那么直接上代码:

#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <asm/uaccess.h>#include <linux/input.h>#include <asm/io.h>#include <linux/kernel.h>#include <mach/gpio.h>#include <linux/irq.h>#include <asm/bitops.h>#define _HIGH               1#define _LOW                0#define _ZERO               0enum button_event {    _EV_UP,    _EV_DOWN,};struct buttons_desc{    int gpio;       //PHY button Addr    int keycode;        // button keycode    char *name;         // button name};static struct buttons_desc buttons_array[] ={    {S5PV210_GPH2(0),KEY_LEFT,"LEFT"},    {S5PV210_GPH2(1),KEY_RIGHT,"RIGHT"},    {S5PV210_GPH2(2),KEY_UP,"UP"},    {S5PV210_GPH2(3),KEY_DOWN,"DOWN"},    {S5PV210_GPH3(0),KEY_MENU,"MENU"},    {S5PV210_GPH3(1),KEY_ENTER,"ENTER"},    {S5PV210_GPH3(2),KEY_BACKSPACE,"BACKSPACE"},    {S5PV210_GPH3(3),KEY_DELETE,"DELETE"},};/*****irq use****/volatile struct buttons_desc *g_buttons_desc_info = NULL;/*****input device use****/static struct input_dev *buttons_input_dev =NULL;/*****timer use****/static struct timer_list buttons_timer;/******func start******//******button irq******/static irqreturn_t smart210_buttons_irq(int irq, void* dev_id){    //get whitch key trigger the irq    g_buttons_desc_info =(volatile struct buttons_desc*)dev_id;    //Eliminate key jitter,delay 10 ms to get key value    mod_timer(&buttons_timer,jiffies + HZ/100);    return IRQ_HANDLED;}/******timer del func******/static void buttons_timer_func(unsigned long data){    int uc_keysta =0;    struct buttons_desc *uc_buttons_desc =(struct buttons_desc *)g_buttons_desc_info;    if(!uc_buttons_desc)    {        return;    }    //get the pin level :high /low    //pree up 0,pree down 1    if(gpio_get_value(uc_buttons_desc->gpio) == _HIGH)    {        uc_keysta =_EV_UP;    }    else    {        uc_keysta =_EV_DOWN;    }    input_event(buttons_input_dev,EV_KEY, uc_buttons_desc->keycode,uc_keysta);    input_event(buttons_input_dev,EV_SYN, _ZERO,_ZERO);}static int __init smart210_buttons_init(void){    int i;    int ret=0;    //1.alloc input dev device    buttons_input_dev = input_allocate_device();    if (!buttons_input_dev)     {        ret = -ENOMEM;        printk("1.error allocate input device!\n");        goto err_allocate_input_dev;    }    //2.set up the input dev param,Report event    //EV_KEY :key event    //EV_SYN: sync event    set_bit(EV_KEY,buttons_input_dev->evbit);    set_bit(EV_SYN,buttons_input_dev->evbit);    set_bit(EV_REP,buttons_input_dev->evbit);    //set EV_KEY key code    for(i =0; i < ARRAY_SIZE(buttons_array);i++)    {        set_bit(buttons_array[i].keycode,buttons_input_dev->keybit);    }    //set input dev name    buttons_input_dev->name = "buttons";    //3.register device    ret = input_register_device(buttons_input_dev);    if(ret)     {        printk("2.error to register input device!\n");        goto err_register_input_dev;    }/******special func user add for different input device*********/    //4.irq request    for(i =0; i < ARRAY_SIZE(buttons_array);i++)    {        ret =request_irq(gpio_to_irq(buttons_array[i].gpio),smart210_buttons_irq,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,                         buttons_array[i].name,&buttons_array[i]);        if(ret)        {            break;        }    }    if(ret)     {        i--;        for(; i >0;i--)        {            if(!buttons_array[i].gpio)            {                continue;            }            disable_irq(gpio_to_irq(buttons_array[i].gpio));            free_irq(gpio_to_irq(buttons_array[i].gpio),&buttons_array[i]);        }        printk("3.error to request irq !\n");        goto err_request_irq;    }    //5.timer initial    init_timer(&buttons_timer);    buttons_timer.function =buttons_timer_func;    add_timer(&buttons_timer);    printk("4.success initial input device!\n");    return 0;err_request_irq:    input_unregister_device(buttons_input_dev);err_register_input_dev:err_allocate_input_dev:    input_free_device(buttons_input_dev);    return ret;}static void __exit smart210_buttons_exit(void){    int i;    del_timer(&buttons_timer);    for(i=0;i< ARRAY_SIZE(buttons_array);i++)    {        disable_irq(gpio_to_irq(buttons_array[i].gpio));        free_irq(gpio_to_irq(buttons_array[i].gpio),&buttons_array[i]);    }    input_unregister_device(buttons_input_dev);    input_free_device(buttons_input_dev);    printk("5.success unload input device!\n");}module_init(smart210_buttons_init);module_exit(smart210_buttons_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("User");

实验现象:
input设备注册成功后,cat/proc/interrupts下面会有你的中断号:
这里写图片描述
第一列:中断号
第二列:响应的次数,没有响应中断就是0
第三列:中断类型
第四列:中断的name

同样,dev/input/目录下面会多一个event*设备文件,主设备号13,次设备号自动分配.
我们可以操作这个设备文件:
这里写图片描述
以16进制的格式显示event1中的数据。里面的数据含义如下:
这里写图片描述

同时,在 proc/bus/input/下面会有devices和 handlers两个文件

devices:
这里写图片描述
这里面两个输入设备,一个是TS的,一个是按键的.
handlers:
这里写图片描述
这里面有4个handlers,其中evdev是我们按键的,mousedev是鼠标的.其他的不清楚

整个input设备注册的流程:

input device register procedure:1.alloc input dev device/*****input device use****/static struct input_dev *buttons_input_dev =NULL;buttons_input_dev =input_allocate_device();2. fill in/ initial the  struct buttons_input_dev    //set up the input dev param,Report event    //EV_KEY :key event    //EV_SYN: sync event    set_bit(EV_KEY,buttons_input_dev->evbit);    set_bit(EV_SYN,buttons_input_dev->evbit);    set_bit(EV_REP,buttons_input_dev->evbit);    //set EV_KEY key code    set_bit(buttons_array[0].keycode,buttons_input_dev->keybit);    //set input dev name    buttons_input_dev->name = "buttons";3.register input device    ret = input_register_device(buttons_input_dev);/*****input device register end****/4. Report event:    input_event(buttons_input_dev,EV_KEY, uc_buttons_desc->keycode,uc_keysta);    input_event(buttons_input_dev,EV_SYN, _ZERO,_ZERO);//EV_SYN must have ,its finish end flag5. cancle /logout the device:    input_unregister_device(buttons_input_dev);6. free the input dev:    input_free_device(buttons_input_dev);all the above is the frame of input system.

标准的输入子系统的注册大概就是这样的。

测试程序:

#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<linux/input.h>struct input__event{    struct timeval time;    __u16 type;    __u16 code;    __s32 value;};int fd;int main(){    struct input__event ev_key;    fd = open("/dev/input/event1",O_RDWR);    printf("fd =%d,\n",fd);    while(1)    {        read(fd,&ev_key,sizeof(ev_key));        if(ev_key.type == EV_KEY)        {            printf("time:%ld s,%ld us,type: %d,code:%d,vale:%d.\n",ev_key.time.tv_sec,ev_key.time.tv_usec,ev_key.type,ev_key.code,ev_key.value);        }    }    return 0;}

用户空间调用open,read函数读按键值出来:

这样,按键的驱动和测试程序都已完成.

0 0
原创粉丝点击