版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127
三.测试代码
至此为止,我们已经讲完了输入子系统的设备驱动层,核心层,事件处理层的关系和相关代码,现在,我们通过基于Mini2440的开发板,将输入子系统融入按键驱动,编写设备驱动程序,动态加载到内核,并且编写应用层程序,测试按键驱动。
我们已经配置了mini2440的串口配置,然后根据mini2440开发板的硬件电路知道S3C2440总共有6个用户测试用按键,它们均从CPU中断引脚直接引出,属于低电平触发,这些引脚也可以复用为GPIO和特殊功能口,为了用户把它们引出作为其他用途,这6个引脚也通过CON12 引出,6个按键和CON12的定义如下:
在该实验中,我们只测试KEY1,对应的中断号为EINT8。
实验环境:内核linux2.6.32.2,arm-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