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