輸入設備(如鼠標,鍵盤,觸摸屏,撥碼開關,按鍵,麥克風,遊戲搖桿,遊戲手柄等)是典型的字符設備。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
運行測試: