Input子系统概述
Input驱动编写流程
1767 struct class input_class = { 1768 .name = "input", 1769 .devnode = input_devnode, 1770 }; ...... 2414 static int __init input_init(void) 2415 { 2416 int err; 2417 2418 err = class_register(&input_class); 2419 if (err) { 2420 pr_err("unable to register input_dev class\n"); 2421 return err; 2422 } 2423 2424 err = input_proc_init(); 2425 if (err) 2426 goto fail1; 2427 2428 err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), 2429 INPUT_MAX_CHAR_DEVICES, "input"); 2430 if (err) { 2431 pr_err("unable to register char major %d", INPUT_MAJOR); 2432 goto fail2; 2433 } 2434 2435 return 0; 2436 2437 fail2: input_proc_exit(); 2438 fail1: class_unregister(&input_class); 2439 return err; 2440 }注册input_dev
。。。
上报输入事件
。。。
input_event结构体
实验程序编写
修改设备树
使用key按键节点的设备树
按键input驱动程序编写
keyinput.c
1 #include <linux/types.h> 2 #include <linux/kernel.h> 3 #include <linux/delay.h> 4 #include <linux/ide.h> 5 #include <linux/init.h> 6 #include <linux/module.h> 7 #include <linux/errno.h> 8 #include <linux/gpio.h> 9 #include <linux/cdev.h> 10 #include <linux/device.h> 11 #include <linux/of.h> 12 #include <linux/of_address.h> 13 #include <linux/of_gpio.h> 14 #include <linux/input.h> 15 #include <linux/semaphore.h> 16 #include <linux/timer.h> 17 #include <linux/of_irq.h> 18 #include <linux/irq.h> 19 #include <asm/mach/map.h> 20 #include <asm/uaccess.h> 21 #include <asm/io.h> 32 #define KEYINPUT_CNT 1 /* 设备号个数 */ 33 #define KEYINPUT_NAME "keyinput" /* 名字 */ 34 #define KEY0VALUE 0X01 /* KEY0 按键值 */ 35 #define INVAKEY 0XFF /* 无效的按键值 */ 36 #define KEY_NUM 1 /* 按键数量 */ 37 38 /* 中断 IO 描述结构体 */ 39 struct irq_keydesc { 40 int gpio; /* gpio */ 41 int irqnum; /* 中断号 */ 42 unsigned char value; /* 按键对应的键值 */ 43 char name[10]; /* 名字 */ 44 irqreturn_t (*handler)(int, void *); /* 中断服务函数 */ 45 }; 46 47 /* keyinput 设备结构体 */ 48 struct keyinput_dev{ 49 dev_t devid; /* 设备号 */ 50 struct cdev cdev; /* cdev */ 51 struct class *class; /* 类 */ 52 struct device *device; /* 设备 */ 53 struct device_node *nd; /* 设备节点 */ 54 struct timer_list timer; /* 定义一个定时器 */ 55 struct irq_keydesc irqkeydesc[KEY_NUM]; /* 按键描述数组 */ 56 unsigned char curkeynum; /* 当前的按键号 */ 57 struct input_dev *inputdev; /* input 结构体 */ 58 }; 59 60 struct keyinput_dev keyinputdev; /* key input 设备 */ 61 62 /* @description : 中断服务函数,开启定时器,延时 10ms, 63 * 定时器用于按键消抖。 64 * @param - irq : 中断号 65 * @param - dev_id : 设备结构。 66 * @return : 中断执行结果 67 */ 68 static irqreturn_t key0_handler(int irq, void *dev_id) 69 { 70 struct keyinput_dev *dev = (struct keyinput_dev *)dev_id; 71 72 dev->curkeynum = 0; 73 dev->timer.data = (volatile long)dev_id; 74 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10)); 75 return IRQ_RETVAL(IRQ_HANDLED); 76 } 77 78 /* @description : 定时器服务函数,用于按键消抖,定时器到了以后 79 * 再次读取按键值,如果按键还是处于按下状态就表示按键有效。 80 * @param - arg : 设备结构变量 81 * @return : 无 82 */ 83 void timer_function(unsigned long arg) 84 { 85 unsigned char value; 86 unsigned char num; 87 struct irq_keydesc *keydesc; 88 struct keyinput_dev *dev = (struct keyinput_dev *)arg; 89 90 num = dev->curkeynum; 91 keydesc = &dev->irqkeydesc[num]; 92 value = gpio_get_value(keydesc->gpio); /* 读取 IO 值 */ 93 if(value == 0){ /* 按下按键 */ 94 /* 上报按键值 */ 95 //input_event(dev->inputdev, EV_KEY, keydesc->value, 1); 96 input_report_key(dev->inputdev, keydesc->value, 1);/*1,按下*/ 97 input_sync(dev->inputdev); 98 } else { /* 按键松开 */ 99 //input_event(dev->inputdev, EV_KEY, keydesc->value, 0); 100 input_report_key(dev->inputdev, keydesc->value, 0); 101 input_sync(dev->inputdev); 102 } 103 } 104 105 /* 106 * @description : 按键 IO 初始化 107 * @param : 无 108 * @return : 无 109 */ 110 static int keyio_init(void) 111 { 112 unsigned char i = 0; 113 char name[10]; 114 int ret = 0; 115 116 keyinputdev.nd = of_find_node_by_path("/key"); 117 if (keyinputdev.nd== NULL){ 118 printk("key node not find!\r\n"); 119 return -EINVAL; 120 } 121 122 /* 提取 GPIO */ 123 for (i = 0; i < KEY_NUM; i++) { 124 keyinputdev.irqkeydesc[i].gpio = of_get_named_gpio(keyinputdev.nd,"key-gpio", i); 125 if (keyinputdev.irqkeydesc[i].gpio < 0) { 126 printk("can't get key%d\r\n", i); 127 } 128 } 129 130 /* 初始化 key 所使用的 IO,并且设置成中断模式 */ 131 for (i = 0; i < KEY_NUM; i++) { 132 memset(keyinputdev.irqkeydesc[i].name, 0, sizeof(name)); 133 sprintf(keyinputdev.irqkeydesc[i].name, "KEY%d", i); 134 gpio_request(keyinputdev.irqkeydesc[i].gpio, keyinputdev.irqkeydesc[i].name); 135 gpio_direction_input(keyinputdev.irqkeydesc[i].gpio); 136 keyinputdev.irqkeydesc[i].irqnum =irq_of_parse_and_map(keyinputdev.nd, i); 137 } 138 /* 申请中断 */ 139 keyinputdev.irqkeydesc[0].handler = key0_handler; 140 keyinputdev.irqkeydesc[0].value = KEY_0; 141 142 for (i = 0; i < KEY_NUM; i++) { 143 ret = request_irq(keyinputdev.irqkeydesc[i].irqnum, keyinputdev.irqkeydesc[i].handler, 144 IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, keyinputdev.irqkeydesc[i].name, &keyinputdev); 145 if(ret < 0){ 146 printk("irq %d request failed!\r\n",keyinputdev.irqkeydesc[i].irqnum); 147 return -EFAULT; 148 } 149 } 150 151 /* 创建定时器 */ 152 init_timer(&keyinputdev.timer); 153 keyinputdev.timer.function = timer_function; 154 155 /* 申请 input_dev */ 156 keyinputdev.inputdev = input_allocate_device(); 157 keyinputdev.inputdev->name = KEYINPUT_NAME; 158 #if 0 159 /* 初始化 input_dev,设置产生哪些事件 */ 160 __set_bit(EV_KEY, keyinputdev.inputdev->evbit); /*按键事件 */ 161 __set_bit(EV_REP, keyinputdev.inputdev->evbit); /* 重复事件 */ 162 163 /* 初始化 input_dev,设置产生哪些按键 */ 164 __set_bit(KEY_0, keyinputdev.inputdev->keybit); 165 #endif 166 167 #if 0 168 keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_ MASK(EV_REP); 169 keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |=BIT_MASK(KEY_0); 170 #endif 171 172 keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 173 input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0); 174 175 /* 注册输入设备 */ 176 ret = input_register_device(keyinputdev.inputdev); 177 if (ret) { 178 printk("register input device failed!\r\n"); 179 return ret; 180 } 181 return 0; 182 } 183 184 /* 185 * @description : 驱动入口函数 186 * @param : 无 187 * @return : 无 188 */ 189 static int __init keyinput_init(void) 190 { 191 keyio_init(); 192 return 0; 193 } 194 195 /* 196 * @description : 驱动出口函数 197 * @param : 无 198 * @return : 无 199 */ 200 static void __exit keyinput_exit(void) 201 { 202 unsigned int i = 0; 203 /* 删除定时器 */ 204 del_timer_sync(&keyinputdev.timer); 205 206 /* 释放中断*/ 207 for (i = 0; i < KEY_NUM; i++) { 208 free_irq(keyinputdev.irqkeydesc[i].irqnum, &keyinputdev); 209 } 210 /* 释放 IO */ 211 for (i = 0; i < KEY_NUM; i++) { 212 gpio_free(keyinputdev.irqkeydesc[i].gpio); 213 } 214 /* 释放 input_dev */ 215 input_unregister_device(keyinputdev.inputdev); 216 input_free_device(keyinputdev.inputdev); 217 } 218 219 module_init(keyinput_init); 220 module_exit(keyinput_exit); 221 MODULE_LICENSE("GPL"); 222 MODULE_AUTHOR("zipeng");编写测试APP
keyinputApp.c
1 #include "stdio.h" 2 #include "unistd.h" 3 #include "sys/types.h" 4 #include "sys/stat.h" 5 #include "sys/ioctl.h" 6 #include "fcntl.h" 7 #include "stdlib.h" 8 #include "string.h" 9 #include <poll.h> 10 #include <sys/select.h> 11 #include <sys/time.h> 12 #include <signal.h> 13 #include <fcntl.h> 14 #include <linux/input.h> 27 /* 定义一个 input_event 变量,存放输入事件信息 */ 28 static struct input_event inputevent; 29 30 /* 31 * @description : main 主程序 32 * @param - argc : argv 数组元素个数 33 * @param - argv : 具体参数 34 * @return : 0 成功;其他 失败 35 */ 36 int main(int argc, char *argv[]) 37 { 38 int fd; 39 int err = 0; 40 char *filename; 41 42 filename = argv[1]; 43 44 if(argc != 2) { 45 printf("Error Usage!\r\n"); 46 return -1; 47 } 48 49 fd = open(filename, O_RDWR); 50 if (fd < 0) { 51 printf("Can't open file %s\r\n", filename); 52 return -1; 53 } 54 55 while (1) { 56 err = read(fd, &inputevent, sizeof(inputevent)); 57 if (err > 0) { /* 读取数据成功 */ 58 switch (inputevent.type) { 59 case EV_KEY: 60 if (inputevent.code < BTN_MISC) { /* 键盘键值 */ 61 printf("key %d %s\r\n", inputevent.code, inputevent.value ? "press" : "release"); 62 } else { 63 printf("button %d %s\r\n", inputevent.code, inputevent.value ? "press" : "release"); 64 } 65 break; 66 67 /* 其他类型的事件,自行处理 */ 68 case EV_REL: 69 break; 70 case EV_ABS: 71 break; 72 case EV_MSC: 73 break; 74 case EV_SW: 75 break; 76 } 77 } else { 78 printf("读取数据失败\r\n"); 79 } 80 } 81 return 0; 82 }运行测试
编译驱动程序
KERNELDIR := /home/zipeng/linux/myKernel/linux-imxrel_imx_4.1.15_2.1.0_ga ...... 4 obj-m := keyinput.o ...... 11 clean: 12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) cleanmake -j16
编译测试APP
arm-linux-gnueabihf-gcc keyinputApp.c -o keyinputApp
运行测试
将前面编译出来 keyinput.ko和keyinputApp这两个文件拷贝到rootfs/lib/modules/4.1.15
输入如下测试命令: