tiny4412 Linux驱动Input子系统

输入设备(如鼠标,键盘,触摸屏,拨码开关,按键,麦克风,游戏摇杆,游戏手柄等)是典型的字符设备。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
	

运行测试:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章