51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 1556|回复: 0
打印 上一主题 下一主题

linux驱动程序之基于输入子系统写驱动程序

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-6-19 15:39:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
基于输入子系统写按键驱动:

步骤:
    分配input_dev结构体

    设置这个结构体

    注册

    硬件相关操作(有数据产生时调用 input_event来上报)


1、分配input_dev结构体

首先要定义这个结构体:
static struct input_dev *buttons_dev;

然后在init函数中进行以下操作:
buttons_dev = input_allocate_device();
2、设置这个结构体

使用set_bit来设置这一个位。
===========================================================
[cpp] view plain copy
能设置的的东西:  
  1. <p>unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//能产生哪类事件  </p><p>unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//能产生哪些按键  </p><p>unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//能产生哪些相对位移事件x,y,滚轮  </p><p>unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//能产生哪些绝对位移事件,x,y  </p><p>unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  </p><p>unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  </p><p>unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  </p><p>unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  </p><p>unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  </p><p></p>
复制代码


============================================================

/*2.1能产生哪类事件*/
[cpp] view plain copy
set_bit(EV_KEY,buttons_dev->evbit);//EV_KEY表示按键事件  
set_bit(EV_REP,buttons_dev->evbit);//EV_REP表示重复事件  



/*2.2能产生这类操作里的哪些事件 L,S,ENTER,LEFTSHIT*/

3、注册input_register_device(buttons_dev);

  1. <p>[cpp] view plain copy</p><p>set_bit(KEY_L,buttons_dev->keybit);  </p><p>set_bit(KEY_S,buttons_dev->keybit);  </p><p>set_bit(KEY_ENTER,buttons_dev->keybit);  </p><p>set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);  </p><p>
  2. </p><p>
  3. </p><p>4、硬件相关的操作:</p><p>
  4. </p><p>我们使用中断读取按键值,并且使用定时器防止按键抖动:</p><p>1、注册中断,配置引脚</p><p> </p><p>[cpp] view plain copy</p><p>for(i=0;i<4;i++)  </p><p> {  </p><p>     error = request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH,pins_desc[i].name,&pins_desc[i]);  </p><p>     if(error)  </p><p>     {  </p><p>         pr_err("buttons_input: Unable to register input device, "  </p><p>                     "error: %d\n", error);  </p><p>     }  </p><p> }  </p><p>
  5. </p><p>
  6. </p><p>这里说明一下,pins_desc是我定义的一个结构体,定义如下:</p><p>[cpp] view plain copy</p><p>struct pin_desc{  </p><p>    int irq;//中断号  </p><p>    char *name;  </p><p>    unsigned int pin;  </p><p>    unsigned int key_value;  </p><p>};  </p><p>  </p><p>struct pin_desc pins_desc[4] =  </p><p>{  </p><p>    {IRQ_EINT1,"key1",S3C2410_GPF1,KEY_L},  </p><p>    {IRQ_EINT4,"key2",S3C2410_GPF4,KEY_S},  </p><p>    {IRQ_EINT2,"key3",S3C2410_GPF2,KEY_ENTER},  </p><p>    {IRQ_EINT0,"key4",S3C2410_GPF0,KEY_LEFTSHIFT},  </p><p>};  </p><p>
  7. </p><p>
  8. </p><p>这样中断就注册好了,还需要写一个中断处理函数:buttons_irq</p><p>[cpp] view plain copy</p><p>static irqreturn_t buttons_irq(int irq,void *dev_id)  </p><p>{  </p><p>    irq_pd = (struct pin_desc *)dev_id;  </p><p>     /*10ms后启动定时器*/  </p><p>    return IRQ_HANDLED;  </p><p>}  </p><p></p>
复制代码

按键中断中断中现在只获取中断号。由于我们要使用定时器来防止抖动,所以,大部分关于按键的工
作要在定时器服务函数中执行,按键中断的服务程序就先放到这里,等会修改。

2、添加一个定时器并设置。
首先:定义一个定时器结构体:
static struct timer_list button_timer;
在init函数中初始化这个结构体:
init_timer(&button_timer);
定时器有两个要素;时间,处理函数,时间在初始化时不用设置,默认是0。
设置处理函数:
button_timer.function = buttons_timer_function;
通知内核,告诉他这个定时器:
add_timer(&button_timer);

接下来写完成这个定时器处理函数: buttons_timer_function
  1. <p>[cpp] view plain copy</p><p>static void buttons_timer_function(unsigned long data)  </p><p>{  </p><p>    struct pin_desc * pindesc = irq_pd;  </p><p>    unsigned int pinval;  </p><p>    if(!pindesc)  </p><p>        return;  </p><p>    pinval = s3c2410_gpio_getpin(pindesc -> pin);  </p><p>    if(pinval)//松开  </p><p>    {  </p><p>        /*最后一个参数0 表示松开,1表示按下*/  </p><p>        input_event(buttons_dev,EV_KEY,pindesc->key_value,0);  </p><p>        input_sync(buttons_dev);  </p><p>    }  </p><p>    else//按下  </p><p>    {  </p><p>        input_event(buttons_dev,EV_KEY,pindesc->key_value,1);  </p><p>        input_sync(buttons_dev);  </p><p>    }  </p><p>}  </p><p></p>
复制代码


这个函数中主要根据读取的pindesc来判断是按键按下还是松开,继而调用:
input_event(buttons_dev,EV_KEY,pindesc->key_value,0);
input_sync(buttons_dev);
这个函数来发送信号。其中input_event最后一个参数0 表示松开,1表示按下。

那么什么时候触发这个定时器服务函数? 需要修改中断服务程序的内容,来修改定时器:
/*10ms后启动定时器*/
mod_timer(&button_timer,jiffies+HZ/100);
让定时器服务函数在 按键中断的10ms后执行。


测试:
1、 hexdump /dev/event1   (open( /dev/event1 ),read)
    |   秒    ||   微妙  ||类    ||code||value |
0000d80 0221 0000 eba5 0009 0001 0026 0001 0000
0000d90 0221 0000 ebbf 0009 0000 0000 0000 0000
0000da0 0221 0000 950f 000d 0001 0026 0000 0000
0000db0 0221 0000 951f 000d 0000 0000 0000 0000

2、如果没有启动Qt:
cat /dev/tty1
按按键就可以得到键值

或者使用命令:exec 0</dev/tty1
然后使用按键输入


3、如果启动Qt:
可以点开记事本,然后按按键就可以得到数字。
或者在init.d的rcs文件中将qt禁止启动

驱动程序:
  1. <p>
  2. </p><p>[cpp] view plain copy</p><p>//可以参考gpio_keys.c  </p><p>#include <linux/module.h>  </p><p>  </p><p>#include <linux/init.h>  </p><p>#include <linux/fs.h>  </p><p>#include <linux/interrupt.h>  </p><p>#include <linux/irq.h>  </p><p>#include <linux/sched.h>  </p><p>#include <linux/pm.h>  </p><p>#include <linux/sysctl.h>  </p><p>#include <linux/proc_fs.h>  </p><p>#include <linux/delay.h>  </p><p>#include <linux/platform_device.h>  </p><p>#include <linux/input.h>  </p><p>#include <linux/gpio_keys.h>  </p><p>#include <mach/regs-gpio.h>  </p><p>#include <mach/irqs.h>  </p><p>#include <asm/io.h>  </p><p>#include <asm/gpio.h>  </p><p>  </p><p>struct pin_desc{  </p><p>    int irq;//中断号  </p><p>    char *name;  </p><p>    unsigned int pin;  </p><p>    unsigned int key_value;  </p><p>};  </p><p>  </p><p>struct pin_desc pins_desc[4] =  </p><p>{  </p><p>    {IRQ_EINT1,"key1",S3C2410_GPF1,KEY_L},  </p><p>    {IRQ_EINT4,"key2",S3C2410_GPF4,KEY_S},  </p><p>    {IRQ_EINT2,"key3",S3C2410_GPF2,KEY_ENTER},  </p><p>    {IRQ_EINT0,"key4",S3C2410_GPF0,KEY_LEFTSHIFT},  </p><p>};  </p><p>  </p><p>static struct pin_desc *irq_pd;  </p><p>static struct input_dev *buttons_dev;  </p><p>static struct timer_list button_timer;  </p><p>static void buttons_timer_function(unsigned long data)  </p><p>{  </p><p>    struct pin_desc * pindesc = irq_pd;  </p><p>    unsigned int pinval;  </p><p>    if(!pindesc)  </p><p>        return;  </p><p>    pinval = s3c2410_gpio_getpin(pindesc -> pin);  </p><p>    if(pinval)//松开  </p><p>    {  </p><p>        /*最后一个参数0 表示松开,1表示按下*/  </p><p>        input_event(buttons_dev,EV_KEY,pindesc->key_value,0);  </p><p>        input_sync(buttons_dev);  </p><p>    }  </p><p>    else//按下  </p><p>    {  </p><p>        input_event(buttons_dev,EV_KEY,pindesc->key_value,1);  </p><p>        input_sync(buttons_dev);  </p><p>    }  </p><p>}  </p><p>static irqreturn_t buttons_irq(int irq,void *dev_id)  </p><p>{  </p><p>    irq_pd = (struct pin_desc *)dev_id;  </p><p>    /*10ms后启动定时器*/  </p><p>    mod_timer(&button_timer,jiffies+HZ/200);  </p><p>    return IRQ_HANDLED;  </p><p>}  </p><p>static int buttons_init(void)  </p><p>{  </p><p>    int i,error;  </p><p>    /*1、分配一个input_dev结构体*/  </p><p>    buttons_dev = input_allocate_device();  </p><p>    /*2、设置*/  </p><p>    /*2.1能产生哪类事件*/  </p><p>    set_bit(EV_KEY,buttons_dev->evbit);  </p><p>    set_bit(EV_REP,buttons_dev->evbit);  </p><p>    /*2.2能产生这类操作里的哪些事件 L,S,ENTER,LEFTSHIT*/  </p><p>    set_bit(KEY_L,buttons_dev->keybit);  </p><p>    set_bit(KEY_S,buttons_dev->keybit);  </p><p>    set_bit(KEY_ENTER,buttons_dev->keybit);  </p><p>    set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);  </p><p>    /*3、注册*/  </p><p>    input_register_device(buttons_dev);  </p><p>    /*4、硬件相关操作*/  </p><p>    init_timer(&button_timer);  </p><p>    button_timer.function = buttons_timer_function;  </p><p>    add_timer(&button_timer);  </p><p>    for(i=0;i<4;i++)  </p><p>    {  </p><p>        error = request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH,pins_desc[i].name,&pins_desc[i]);  </p><p>        if(error)  </p><p>        {  </p><p>            pr_err("buttons_input: Unable to register input device, "  </p><p>                        "error: %d\n", error);  </p><p>        }  </p><p>    }  </p><p>    return 0;  </p><p>  </p><p>}  </p><p>  </p><p>static void buttons_exit(void)  </p><p>{  </p><p>    int i;  </p><p>    for(i=0;i<4;i++)  </p><p>    {  </p><p>        free_irq(pins_desc[i].irq,&pins_desc[i]);  </p><p>    }  </p><p>    del_timer(&button_timer);  </p><p>    input_unregister_device(buttons_dev);  </p><p>    input_free_device(buttons_dev);  </p><p>}  </p><p>  </p><p>module_init(buttons_init);  </p><p>module_exit(buttons_exit);  </p><p>  </p><p>MODULE_LICENSE("GPL");  </p>
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-4-20 23:44 , Processed in 0.071241 second(s), 24 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表