输入设备(如鼠标,键盘,触摸屏,拨码开关,按键,麦克风,游戏摇杆,游戏手柄等)是典型的字符设备。Linux为了方便统一管理这些设备,然后设计了输入子系统,在Linux中,输入子系统的驱动节点都是有固定的位置的:
在新内核中:
/dev/input/event0 /dev/input/event1 ...
/dev/input/mouse0 /dev/input/mouse1 ...
在旧内核中:
/dev/event0 /dev/event1 ...
/dev/mouse0 /dev/mouse1 ...
驱动节点对应哪个设备
cat /proc/bus/input/devices
控制台捕获驱动节点的信息:
hexdump /dev/input/event0
本次是以4个key按键为例,来编写一个输入子系统,设计一个小键盘驱动,模拟qwer按键,当分别按下开发板上的4个按键时,应用层打印一些内容,验证驱动是否成功。
驱动层input.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <linux/interrupt.h>
#define KEY_GPIO(i) EXYNOS4_GPX3(2+i)
#define KEY_QWER(i) (KEY_Q+i)
struct input_dev *key_dev;
int key_irq[4]={0};
irqreturn_t key_irq_handle(int irq, void *args)
{
int i=0;
for(i = 0; i < 4; i++){
if(irq==key_irq[i]){
//printk("key%d Down!\n", i+1);
input_report_key(key_dev, KEY_QWER(i), !!!gpio_get_value(KEY_GPIO(i)));
input_sync(key_dev);
}
}
return IRQ_HANDLED;
}
static int __init tiny4412_input_init(void)
{
int ret;
int i;
char name[16];
key_dev = input_allocate_device();
if(key_dev == NULL){
printk("input alloc error\n");
return -1;
}
key_dev->name = "biu's mechanical keyboard";
//把evbit数组里的EV_KEY位使能,也就表明这个设备是一个key设备
set_bit(EV_KEY, key_dev->evbit);
//让该设备支持qwer键
for(i=0;i<4;i++){
set_bit(KEY_QWER(i), key_dev->keybit);
}
for(i=0; i<4; i++){
memset(name, 0, sizeof(name));
sprintf(name, "key%d_irq", i);
key_irq[i] = gpio_to_irq(KEY_GPIO(i));
ret = request_irq(key_irq[i], key_irq_handle, IRQF_DISABLED | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,name, (void*)i);
if(ret < 0){
printk("request irq error\n");
goto err_irq;
}
}
ret = input_register_device(key_dev);
if(ret < 0){
printk("input register error\n");
goto err_input;
}
return 0;
err_input:
while(i--){
free_irq(key_irq[i], NULL);
}
err_irq:
input_free_device(key_dev);
return ret;
}
static void __exit tiny4412_input_exit(void)
{
int i = 4;
while(i--){
free_irq(key_irq[i], (void*)i);
}
input_unregister_device(key_dev);
input_free_device(key_dev);
}
module_init(tiny4412_input_init);
module_exit(tiny4412_input_exit);
MODULE_LICENSE("GPL");
应用层app_input.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/input.h>
int main(int argc, char **argv)
{
int fd;
struct input_event event;
fd = open(argv[1],O_RDWR);
if(fd < 0){
perror("open error:");
return fd;
}
while(1){
read(fd,&event,sizeof(event));
if(event.type == EV_KEY){
if(event.code == KEY_Q){
printf("Q:霸王拳\n");
}
if(event.code == KEY_W){
printf("W:降龙十八掌\n");
}
if(event.code == KEY_E){
printf("E:狂龙乱舞\n");
}
if(event.code == KEY_R){
printf("R:流星赶月\n");
}
}
}
close(fd);
return 0;
}
Makefile
obj-m += input.o
KERN_DIR=/root/work/tiny4412/linux/linux-3.5
PWD := $(shell pwd)
modules:
$(MAKE) ARCH=arm -C $(KERN_DIR) M=$(PWD) modules
arm-linux-gcc app_input.c -o app
cp app input.ko /root/work/tiny4412/rootfs/root_nfs/root/input
clean:
$(MAKE) ARCH=arm -C $(KERN_DIR) M=$(PWD) modules clean
运行测试: