现在的位置: 首页 > 综合 > 正文

Linux下的Input子系统(三)

2013年09月01日 ⁄ 综合 ⁄ 共 3774字 ⁄ 字号 评论关闭

版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127

三.测试代码

至此为止,我们已经讲完了输入子系统的设备驱动层,核心层,事件处理层的关系和相关代码,现在,我们通过基于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_devopen函数

channel->close = button_close; //input_devclose函数

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

抱歉!评论已关闭.