input子系统(三)

三.测试代码

至此为止,我们已经讲完了输入子系统的设备驱动层,核心层,事件处理层的关系和相关代码,现在,我们通过基于Mini2440的开发板,将输入子系统融入按键驱动,编写设备驱动程序,动态加载到内核,并且编写应用层程序,测试按键驱动。

我们已经配置了mini2440的串口配置,然后根据mini2440开发板的硬件电路知道S3C2440总共有6个用户测试用按键,它们均从CPU中断引脚直接引出,属于低电平触发,这些引脚也可以复用为GPIO和特殊功能口,为了用户把它们引出作为其他用途,这6个引脚也通过CON12引出,6个按键和CON12的定义如下:

在该实验中,我们只测试KEY1,对应的中断号为EINT8

实验环境:内核linux2.6.32.2arm-linux-gcc交叉编译器,mini2440开发板

内核配置:选中Evdev.c,主要input.c是已经默认配置进内核的,配置界面如下所示

3.1设备驱动层代码:

#include <linux/input.h>

#include <linux/module.h>

#include <linux/init.h>

#include <asm/irq.h>

#include <asm/io.h>

#include <linux/interrupt.h>

#include <linux/gpio.h>

#include <linux/delay.h>

#include <linux/workqueue.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

struct gpio_button_data {

       struct input_dev *input;

       struct timer_list timer;

       struct work_struct work;

};
 
static struct input_dev *channel=NULL;  

static struct gpio_button_data *button_dev=NULL;//私有数据

static volatile int ev_press = 0;              //按键值

static volatile char key_values [] = {'0'};    //按键标识

static void gpio_keys_report_event(struct work_struct *work)

{    

       key_values[0] = '0' ;     //清除按键标识

       input_report_key(channel, BTN_0, !!ev_press);  //向input子系统报告按键事件

       input_sync(channel);                      //同步操作

      ev_press = 0;                             //清除按键值

}

static void gpio_keys_timer(unsigned long a)
{
       schedule_work(&button_dev->work);  //调度工作队列处理函数
}

static irqreturn_t gpio_keys_isr(int irq, void *dummy)
{
    unsigned int tmp;
    tmp=s3c2410_gpio_getpin(S3C2410_GPG(0));    //读取按键

    if (tmp == (key_values[0] & 1)) { //有按键
       key_values[0] = '1' ;
        ev_press = 1;

    }
      schedule_work(&button_dev->work);   //调度工作队列处理函数
      mod_timer(&button_dev->timer,jiffies+1);  //修改定时时间
      return IRQ_HANDLED;
}

static int button_open(struct input_dev *dev)
{    
       if (request_irq(IRQ_EINT8, gpio_keys_isr, IRQ_TYPE_EDGE_FALLING, "button", button_dev))   //注册中断处理函数
       {
              printk(KERN_ERR "button.c: Can't allocate irq %d\n", IRQ_EINT8);
               return -EBUSY;
       }
       setup_timer(&button_dev->timer,  gpio_keys_timer, (unsigned long)button_dev);   //设置定时器
       INIT_WORK(&button_dev->work, gpio_keys_report_event);                           //设置工作队列

        return 0;
}

static void button_close(struct input_dev *dev)
{    

       free_irq(IRQ_EINT8, button_dev);       //释放中断号

       del_timer_sync(&button_dev->timer);         //删除定时器

       cancel_work_sync(&button_dev->work);    //删除工作队列
}

static int __init button_init(void)
 { 
    int error;

    button_dev = kzalloc(sizeof(struct gpio_button_data),GFP_KERNEL);  //分配gpio_button_data空间

       channel= input_allocate_device();     //分配input_dev空间

       channel->name = "test_button";             //input_dev名字

       channel->evbit[0] = BIT_MASK(EV_KEY);  //支持按键事件

       channel->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);     //支持一个按键

       channel->open = button_open;                   //input_dev的open函数

       channel->close = button_close;           //input_dev的close函数

       error = input_register_device(channel);    //注册input_dev到输入子系统

       button_dev->input=channel;

       if (error)

        { printk(KERN_ERR "button.c: Failed to register device\n");

              goto err_free_dev; }

       return 0;

 err_free_dev:

       input_free_device(channel);

       return error;

}

static void __exit button_exit(void)

{    
       input_unregister_device(channel);            //注销input_dev

       input_free_device(channel);                 //释放input_dev空间

       kfree(button_dev);                          //释放gpio_button_data空间
}

module_init(button_init);

module_exit(button_exit);

MODULE_LICENSE("GPL");

3.2应用层测试代码

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <linux/input.h>

#include <sys/fcntl.h>

int main(int argc, char *argv[])

{

       int fd = -1;

       int num;

       size_t rb;

       int version;

       char name[20];

       struct input_event ev;

       int i=0;

       if ((fd = open("/dev/input/event1", O_RDONLY)) < 0)  //打开设备

       {
              perror("open error");

              exit(1);

       }

       while(1)

       {
              rb = read(fd, &ev, sizeof(struct input_event));  //读取设备

              if (rb < (int)sizeof(struct input_event))  //读取错误

              {

                     perror("read error");

                     exit(1);

              }

              if (EV_KEY==ev.type)                     //读取的是否是按键内容

              {

                     if (1 == ev.value)                   //key1被按下

                     printf("key is pressed\n");

                     else                                 //key1被释放

                     printf("key is released\n");

              }     

       }    

        close(fd);

       return 0;

}

3.3测试过程和结果

虚拟机:

1.编译driver.c生成driver.ko

如下为编译驱动的Makefile

obj-m   := driver.o

       KERNELDIR  := /home/install-file/kernel/linux-2.6.32.2  // linux-2.6.32.2内核路径

       PWD  := $(shell pwd)

default:

       $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

2.编译测试程序test.c

arm-linux-gcc test.c –o test

超级终端:

insmod driver.ko

./test

测试结果:(按下key1键)

key is pressed

key is released




你可能感兴趣的:(input子系统(三))