- 前言
- 一、代码编写
- 1.input_subsystem.c文件
- 2.Makefile文件
- 3.app.c文件
- 二、运行结果
- 总结
本文的主要内容是Linux下输入子系统的案例介绍。
一、代码编写
本代码的例程本来是带有定时器和按键消抖代码的,但是运行的过程有错误,因此,在超时处理函数中处理的内容调在了中断服务函数,将定时器和按键消抖一应代码都删掉了,但不影响最终的运行结果。
1.input_subsystem.c文件#include2.Makefile文件#include #include #include #include #include #include #include #include #include #include struct input_dev *test_dev; //static void timer_function(unsigned long data); struct device_node *test_device_node; struct property *test_node_property; int gpio_num; int irq; //DEFINE_TIMER(test_timer,timer_function,0,0); //静态定义结构体变量并且初始化function,expires,data成员 irq_handler_t test_key(int irq, void *args) //中断服务函数 { printk("test_key trigger off!n"); //test_timer.expires = jiffies + msecs_to_jiffies(20); //延时20ms //add_timer(&test_timer); //向Linux内核注册定时器 int value; value = !gpio_get_value(gpio_num); input_report_key(test_dev,KEY_1,value); input_sync(test_dev); return IRQ_HANDLED; } int dts_probe(struct platform_device *pdev) { int ret = 0; printk("dts_probe matching ok!n"); test_device_node = of_find_node_by_path("/test_key"); //在设备树节点中查找test_key这个节点 if(test_device_node == NULL){ printk("of_find_node_by_path is error!n"); return -1; } gpio_num = of_get_named_gpio(test_device_node,"key-gpio",0); if(gpio_num < 0){ printk("of_get_named_gpio is error!n"); return -1; } gpio_direction_input(gpio_num); //输入 //irq = gpio_to_irq(gpio_num); irq = irq_of_parse_and_map(test_device_node,0); //与上面这句代码的作用相同 printk("irq is %dn", irq); ret = request_irq(irq, test_key, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "test_key", NULL); //IRQF_TRIGGER_RISING为上升沿触发,定义在/linux-4.1.15/include/linux/interrupt.h中 if(ret < 0){ printk("request_irq is error!n"); return -1; } test_dev = input_allocate_device(); test_dev->name = "test_key"; _set_bit(EV_KEY,test_dev->evbit); _set_bit(KEY_1,test_dev->keybit); ret = input_register_device(test_dev); if(ret < 0){ printk("input_register_device is error!n"); return -1; } return 0; } int dts_remove(struct platform_device *pdev) { printk("dts_remove!n"); return 0; } const struct platform_device_id dts_idtable = { .name = "dts_test1" //匹配优先级 第二 }; const struct of_device_id of_match_table_test[] = { {.compatible = "led_keys"}, //匹配优先级 第一 {} }; struct platform_driver dts_device = { .probe = dts_probe, .remove = dts_remove, .driver = { .owner = THIS_MODULE, .name = "dts_test2", //匹配优先级 第三 .of_match_table = of_match_table_test }, .id_table = &dts_idtable }; static int dts_driver_init(void) { int ret = 0; ret = platform_driver_register(&dts_device); if(ret < 0) { printk("platform_driver_register error!n"); return ret; } printk("platform_driver_register ok!n"); return 0; } static int dts_driver_exit(void) { printk("dts_driver_exit!n"); free_irq(irq,NULL); //del_timer(&test_timer); platform_driver_unregister(&dts_device); input_unregister_device(test_dev); } module_init(dts_driver_init); module_exit(dts_driver_exit); MODULE_LICENSE("GPL");
obj-m += input_subsystem.o KDIR:=/linux/linux-4.1.15 PWD?=$(shell pwd) all: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean3.app.c文件
#include#include #include #include #include #include int main(int argc, char *argv[]) { int fd; struct input_event test_event; fd = open("/dev/input/event2", O_RDWR); //这里的"/dev/input/event2"根据开发板上新生成的输入设备添加 if(fd < 0){ perror("open errorn"); return fd; } while(1){ read(fd, &test_event, sizeof(test_event)); if(test_event.type == EV_KEY) { printf("type is %#x.n",test_event.type); printf("code is %#x.n",test_event.code); printf("value is %#x.n",test_event.value); } } return 0; }
二、运行结果
将上面的代码写好之后编译,然后将驱动和经arm编辑器编译的app文件发送至开发板。
先使用如下命令查看开发板上的输入节点有哪些。
ls /dev/input
然后用如下命令查看输入设备的详细信息。
cat /proc/bus/input/devices
打印结果如下。
加载驱动,再使用上述命令查看有没有新的输入设备生成,打印结果如下。
很明显,有event2这个输入设备新生成。
接着使用如下命令测试该输入设备是否可用。
hexdump /dev/input/event2
注意这里的event2,要根据自己新生成的输入设备名添加。
然后按下按键,打印结果如下。
这里的类型EV_KEY和按键KEY_1都是定义在/linux-4.1.15/include/uapi/linux/input.h文件中的,截图如下。
在驱动已经加载的情况下,运行app程序,多次按下按键后的部分结果如下图。
总结
以上就是Linux下输入子系统案例的所有内容了。
本文参考视频:https://www.bilibili.com/video/BV1Vy4y1B7ta?p=43。



