14.2 input子系统——按键驱动

上一节我们知道,写符合输入子系统框架的驱动程序的步骤为:

1. 分配一个input_dev结构体

2. 设置

3. 注册

4. 硬件相关的代码,比如在中断服务程序里上报事件

参考我们/*参考gpio_keys.c代码和他的probe函数*/

input子系统的主设备号为13

1.写出输入子系统框架代码:

/*参考gpio_keys.c代码和他的probe函数*/
#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 <linux/irq.h>
#include <linux/gpio_keys.h>

#include <asm/gpio.h>


struct input_dev *input_mybuttons_dev;
static int input_mybuttons_init(void)
{
    /*1.分配一个input_dev结构体*/
    input_mybuttons_dev = input_allocate_device();

    /*2.设置结构体*/
    //2.1设置结构体的evbit,表示能产生按键类事件
    set_bit(EV_KEY,input_mybuttons_dev->evbit);
    set_bit(EV_REP,input_mybuttons_dev->evbit);//产生重复类事件,会调用定时器,如一直按下按键一直输入键值

    //2.2设置结构体的evbit,表示能产生按键类事件
    set_bit(KEY_L,input_mybuttons_dev->keybit);
    set_bit(KEY_S,input_mybuttons_dev->keybit);
    set_bit(KEY_ENTER,input_mybuttons_dev->keybit);
    set_bit(KEY_LEFTSHIFT,input_mybuttons_dev->keybit);
    
    /*3.注册*/
    input_register_device(input_mybuttons_dev);
    /*4.硬件相关操作*/
    

    
    return 0;
}

static void input_mybuttons_exit(void)
{

}

module_init(input_mybuttons_init);
module_exit(input_mybuttons_exit);
MODULE_LICENSE("GPL");

2.硬件相关操作:

复制以前的硬件代码:

修改定义,在init里注册四个中断

主要是mybuttons_irq,mybuttons_irq之前做的是定时器mod_timer。现在也这样

并在init函数里初始化定时器

修改function,以前写的function使用了唤醒,已经kill_fasync发信号。现在这些都不用做,只需要使用input_event上报事件(input_event最终会调用input_handler里的event函数),内核自动就会帮我们实现这些功能。

写出口函数,释放

3.总结:

以前我们要自己写file_operations里要写open,read,write,还要写class_create和class_device_create(创建类设备,和类设备节点)现在都不用写,输入子系统帮我们写好,在evdev里的file_operations。只不过分成了两层:input_handler和input_device以及使用input_allocate_device和input_register_device注册,并在内核代码里实现connect里创建类设备和设备节点。设备名为/dev/eventX:

evdev.c里的evdev_handler里的connect函数

我们只需要做硬件相关的部分就行,即input_device

4.代码:

/*参考gpio_keys.c代码和他的probe函数*/
#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 <linux/irq.h>
#include <linux/gpio_keys.h>

#include <asm/gpio.h>


struct timer_list mybuttons_timer;
struct pin_desc *irq_dev;
struct input_dev *input_mybuttons_dev;
struct pin_desc{
    int irq;
    char *name;
    unsigned int pin;
    unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
    {IRQ_EINT0, "S1",S3C2410_GPF0, KEY_L},
    {IRQ_EINT2, "S2",S3C2410_GPF2, KEY_S},
    {IRQ_EINT11,"S3",S3C2410_GPG3, KEY_ENTER},
    {IRQ_EINT19,"S4",S3C2410_GPG11,KEY_LEFTSHIFT},
};

static irqreturn_t mybuttons_irq(int irq, void *dev_id)
{
    /*让他10ms后启动mybuttons_timerfun*/
    irq_dev=(struct pin_desc *)dev_id;
    mod_timer(&mybuttons_timer,jiffies+HZ/100);//jiffies是当前的tick,HZ代表1s,HZ/100=10ms.jiffies会++到jiffies+10ms后产生定时器中断
    return IRQ_RETVAL(IRQ_HANDLED);
}

static void mybuttons_timerfun(unsigned long p)
{
    unsigned int pinval;
    struct pin_desc *pindesc =irq_dev;
    if(!pindesc)
        return;
    
    pinval = s3c2410_gpio_getpin(pindesc->pin);   //内核提供的读取引脚值的函数
    if(pinval)
    {
        // 松开: 最后一个参数,1为按下,0为松开
        input_event(input_mybuttons_dev,EV_KEY,pindesc->key_val,0);
        input_sync(input_mybuttons_dev);//表示已经上报完
    }
    else
    {
        input_event(input_mybuttons_dev,EV_KEY,pindesc->key_val,1);
        input_sync(input_mybuttons_dev);
    }

}

static int input_mybuttons_init(void)
{
    int i;
    /*1.分配一个input_dev结构体*/
    input_mybuttons_dev = input_allocate_device();

    /*2.设置结构体*/
    //2.1设置结构体的evbit,表示能产生哪一类事件-按键类事件
    set_bit(EV_KEY,input_mybuttons_dev->evbit);
    set_bit(EV_REP,input_mybuttons_dev->evbit);//产生重复类事件,会调用定时器,如一直按下按键一直输入键值
    //2.2设置结构体的evbit,表示能产生按键类事件
    set_bit(KEY_L,input_mybuttons_dev->keybit);
    set_bit(KEY_S,input_mybuttons_dev->keybit);
    set_bit(KEY_ENTER,input_mybuttons_dev->keybit);
    set_bit(KEY_LEFTSHIFT,input_mybuttons_dev->keybit);
    
    /*3.注册*/
    input_register_device(input_mybuttons_dev);
    /*4.硬件相关操作*/
    /*初始化定时器,为了防抖动*/
    init_timer(&mybuttons_timer); //初始化定时器
    //mybuttons_timer.data     = (unsigned long) SCpnt;  //function的传参,不用可省略
    //mybuttons_timer.expires  = jiffies + 100*HZ;   /* 超时时间,放在中断处理函数使用,没有设置默认=0,即fuction会立即执行 */
    mybuttons_timer.function = mybuttons_timerfun;
    add_timer(&mybuttons_timer);

    
    /*注册四个中断*/
    for(i=0;i<4;i++)
    {
       request_irq(pins_desc[i].irq,mybuttons_irq, IRQT_BOTHEDGE,pins_desc[i].name,&pins_desc[i]);
    }
    
    
    return 0;
}

static void input_mybuttons_exit(void)
{
    int i;
    for(i=0;i<4;i++)
    {
        free_irq(pins_desc[i].irq,&pins_desc[i]);
    }
    del_timer(&mybuttons_timer);
    input_unregister_device(input_mybuttons_dev);
    input_free_device(input_mybuttons_dev);
}

module_init(input_mybuttons_init);
module_exit(input_mybuttons_exit);
MODULE_LICENSE("GPL");

5.测试:

直接insmod input_mybuttons.ko

ls -l /dev/event*

就可以看到已经装载了驱动/dev/event1

方法一:

# hexdump   /dev/event1

hexdump   /dev/event1   会去做:

1.open( /dev/event1);

2.read();      //调用evdev_read函数,最终把结构体input_event  copy_to_user(发到用户空间),这样应用空间就可以读到

执行 hexdump   /dev/event1,按下按键1,打印出:

# hexdump   /dev/event1

                                  秒                微妙        类     code            值

按下:0000000   0046 0000   fe20 0000   0001   0026    0001 0000

           0000010   0046 0000   fe2a 0000   0000   0000    0000 0000

松开:0000020   0046 0000   8092 0004   0001   0026    0000 0000

           0000030   0046 0000   809a 0004   0000   0000    0000 0000

因为1表示按下,0表示松开,code显示如上,所以上面的输出是对的

方法二:

# cat /dev/tty1(没有启动QT的话)

执行后按下按键123,会打印

ls

什么是tty1?

主设备号为4,此设备号为1,是通过tty1_io.c去访问到keyboard.c

方法三:

执行exec 0</dev/tty1   (把/dev/tty1的输入重定位到标准输入)

环形缓冲区:

发布了114 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40535588/article/details/90754745