驱动开发之输入子系统:
输入子系统
事件处理层:drivers/input/evdev.c 给应用层提供统一的交互接口
核心层:drivers/input/input.c 承上启下(提供的接口会被设备驱动调用,调用后会访问事件处理层)
设备驱动层:自己实现,操作硬件
xxx子系统意义:
内核实现的,为了提高代码的通用性
vi drivers/input/input.c
2401 static int __init input_init(void)
2402 {
2405 err = class_register(&input_class);//创建设备类
2411 err = input_proc_init();//在/proc目录下创建input文件夹
2415 err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), //INPUT_MAJOR 为13 说明所有的输入子系统,使用的主设备号都是13
2416 INPUT_MAX_CHAR_DEVICES, "input");
静态注册设备号
}
vi Documetation/devices.txt
488 13 char Input core
489 0 = /dev/input/js0 First joystick 游戏手柄
490 1 = /dev/input/js1 Second joystick
491 ...
492 32 = /dev/input/mouse0 First mouse 鼠标
493 33 = /dev/input/mouse1 Second mouse
494 ...
495 63 = /dev/input/mice Unified mouse 通用鼠标
496 64 = /dev/input/event0 First event queue 除了手柄和鼠标之外的其他输入设备
497 65 = /dev/input/event1 Second event queue
498 ...
通过输入子系统来实现驱动,基本操作过程:
1、给指定的结构体申请空间
1 struct input_dev *input_allocate_device(void)
给struct input_dev申请空间
2、基本配置
3、将申请好的结构体注册到内核中
1 int input_register_device(struct input_dev *dev)
4、操作硬件
2067 int input_register_device(struct input_dev *dev)
------>
2138 input_attach_handler(dev, handler);
------->
991 error = handler->connect(handler, dev, id);
-------->
进入事件处理层
1202 static struct input_handler evdev_handler = {
1203 .event = evdev_event,
1204 .events = evdev_events,
1205 .connect = evdev_connect,
1206 .disconnect = evdev_disconnect,
1207 .legacy_minors = true,
1208 .minor = EVDEV_MINOR_BASE,
1209 .name = "evdev",
1210 .id_table = evdev_ids,
1211 };
---------->
1065 static const struct file_operations evdev_fops = {
1066 .owner = THIS_MODULE,
1067 .read = evdev_read,
1068 .write = evdev_write,
1069 .poll = evdev_poll,
1070 .open = evdev_open,
1071 .release = evdev_release,
1072 .unlocked_ioctl = evdev_ioctl,
1073 #ifdef CONFIG_COMPAT
1074 .compat_ioctl = evdev_ioctl_compat,
1075 #endif
1076 .fasync = evdev_fasync,
1077 .flush = evdev_flush,
1078 .llseek = no_llseek,
1079 };
1113 static int evdev_connect(struct input_handler *handler, struct input_dev *d
1114 const struct input_device_id *id)
1115 {
1116 struct evdev *evdev;
1117 int minor;
1118 int dev_no;
1119 int error;
1120
//获取次设备号
1121 minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
1128 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
1140 dev_no = minor;
1142 if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
1143 dev_no -= EVDEV_MINOR_BASE;
1144 dev_set_name(&evdev->dev, "event%d", dev_no);//创建设备文件
1161 cdev_init(&evdev->cdev, &evdev_fops);
1162 evdev->cdev.kobj.parent = &evdev->dev.kobj;
1163 error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
}
字符设备框架的基本搭建过程:
定义出各种接口函数; //已实现
struct file_operations fops = { //已实现
.owner = ,
.open = ,
.read = ,
.....
};
加载函数
{
设备号 = MKDEV(主设备号,次设备号);
register_chrdev_region(起始设备号,,);//已实现
kzalloc();//申请空间,已实现
cdev_init();//已实现
cdev_add();//已实现
class_create();//创建设备类 已实现
device_create();//创建设备文件 已实现
}
总结:只要调用了input_register_chrdev()那么字符设备框架以及函数接口都可以被创建。
vi -t input_event
421 void input_event(struct input_dev *dev,
422 unsigned int type, unsigned int code, int value)
423 {
424 unsigned long flags;
425
426 if (is_event_supported(type, dev->evbit, EV_MAX)) {//保证为真
427
428 spin_lock_irqsave(&dev->event_lock, flags);
429 input_handle_event(dev, type, code, value);
430 spin_unlock_irqrestore(&dev->event_lock, flags);
431 }
432 }
1 void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value) //
调用唤醒接口
参数1:
参数2:事件的类型
143 #define EV_SYN 0x00
144 #define EV_KEY 0x01
145 #define EV_REL 0x02
146 #define EV_ABS 0x03
147 #define EV_MSC 0x04
148 #define EV_SW 0x05
149 #define EV_LED 0x11
150 #define EV_SND 0x12
151 #define EV_REP 0x14
152 #define EV_FF 0x15
153 #define EV_PWR 0x16
154 #define EV_FF_STATUS 0x17
155 #define EV_MAX 0x1f
参数3:某种事件下,使用的具体值
参数4:状态值,如果使用了按键,0代表按键按下状态,1代表按键抬起状态,
2代表的只关心按下状态内核源码如下:
------->
368 disposition = input_get_disposition(dev, type, code, value);
------>
281 case EV_KEY:
282 if (is_event_supported(code, dev->keybit, KEY_MAX)) {
283
284 /* auto-repeat bypasses state updates */
285 if (value == 2) {
286 disposition = INPUT_PASS_TO_HANDLERS;
287 break;
288 }
289
290 if (!!test_bit(code, dev->key) != !!value) {
291
292 __change_bit(code, dev->key);
293 disposition = INPUT_PASS_TO_HANDLERS ;//结果为1
294 }
295 }
296 break;
参数4可以有逻辑真、逻辑假、可以是2。内核源码如下:
376 if (disposition & INPUT_PASS_TO_HANDLERS) { 377 struct input_value *v; 378 379 if (disposition & INPUT_SLOT) { //条件为假 380 v = &dev->vals[dev->num_vals++]; 381 v->type = EV_ABS; 382 v->code = ABS_MT_SLOT; 383 v->value = dev->mt->slot; 384 } 385 386 v = &dev->vals[dev->num_vals++]; 387 v->type = type; //对结构体成员初始化,给别人用的 388 v->code = code; 389 v->value = value; 390 } 396 } else if (dev->num_vals >= dev->max_vals - 2) { 397 dev->vals[dev->num_vals++] = input_value_sync; 398 input_pass_values(dev, dev->vals, dev->num_vals); 399 dev->num_vals = 0; 400 } static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1}; type = EV_SYN code = SYN_REPORT value = 1; -------> 143 count = input_to_handler(handle, vals, count); ------> 116 if (handler->events) 117 handler->events(handle, vals, count); 如果条件成立则会调用evdev.c中的evdev_events函数 -----------> 1202 static struct input_handler evdev_handler = { 1203 .event = evdev_event, 1204 .events = evdev_events, 1205 .connect = evdev_connect, 1206 .disconnect = evdev_disconnect, 1207 .legacy_minors = true, 1208 .minor = EVDEV_MINOR_BASE, 1209 .name = "evdev", 1210 .id_table = evdev_ids, 1211 }; 进入事件处理层: 197 static void evdev_events(struct input_handle *handle, 198 const struct input_value *vals, unsigned int count) 199 { 211 if (client) 212 evdev_pass_values(client, vals, count, time_mono, time_real); } -------> 179 for (v = vals; v != vals + count; v++) { 180 event.type = v->type; //将type code value的值存放给struct input_event结构体 181 event.code = v->code; 182 event.value = v->value; 183 __pass_event(client, &event); 184 if (v->type == EV_SYN && v->code == SYN_REPORT) //最初type=EV_KEY code=KEY_2 185 wakeup = true; 186 } 187 188 spin_unlock(&client->buffer_lock); 189 190 if (wakeup) 191 wake_up_interruptible(&evdev->wait);//正常的需求下要调用唤醒接口。 //为了保证调用唤醒接口,必须要保证type=EV_SYN code=SYN_REPORT
如何保证?调用input_sync();
1 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口
应用层中调用read(fd,&ev,sizeof(ev));实际上在驱动中会调用事件处理层定义的read函数
vi drivers/input/evdev.c:
vi drivers/input/evdev.c:
484 static ssize_t evdev_read(struct file *file, char __user *buffer,
485 size_t count, loff_t *ppos)
{
514 if (input_event_to_user(buffer + read, &event))
47 compat_event.time.tv_sec = event->time.tv_sec;
48 compat_event.time.tv_usec = event->time.tv_usec;
49 compat_event.type = event->type;
50 compat_event.code = event->code;
51 compat_event.value = event->value;
52
53 if (copy_to_user(buffer, &compat_event,sizeof(struct input_event_compat)))
524 error = wait_event_interruptible(evdev->wait,client->packet_head != client->tail || !evdev->exist || client->revoked);
}
为什么需要调用set_bit函数?
vi -t input_event
426 if (is_event_supported(type, dev->evbit, EV_MAX)) {
//调用时input_event(EV_KEY,KEY_2,2);传参后type=EV_KEY EV_MAX = 31
-------->
53 static inline int is_event_supported(unsigned int code,unsigned long *bm, unsigned int max)
55 {
56 return code <= max && test_bit(code, bm);
57 }
//code=EV_KEY bm = dev->evbit 数组名 max = 31
103 static inline int test_bit(int nr, const volatile unsigned long *addr)
104 {
105 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
106 }
//nr = EV_KEY addr = dev->evbit 1UL 代表的是unsigned long
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) //<==> 1 / 32 = 0
addr[BIT_WORD(nr)] <==> addr[0] <==> dev->evbit[0];
nr & (BITS_PER_LONG-1) <==> 1 & 31 结果为1
(addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))) //理解为dev->evbit[0] >> 1
//1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)))
//理解为:1 & (dev->evbit[0] >> 1) 保证这个结果为真。暂时还保证不了,此时不知道dev->evbit[0]的值为多少。
//解决方法:可以将一个数值放到dev->evbit[0]中并且保证整个结果为真.具体操作就需要调用set_bit()函数
vi -t set_bit
1 set_bit(EV_KEY,fs4412_idev->evbit)//基本配置
//调用时传递的是:set_bit(EV_KEY,fs4412_idev->evbit)
65 static inline void set_bit(int nr, volatile unsigned long *addr)
66 { nr=EV_KEY=1 addr=fs4412_idev->evbit
67 unsigned long mask = BIT_MASK(nr);
68 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
69 unsigned long flags;
70
71 _atomic_spin_lock_irqsave(p, flags);
72 *p |= mask;
73 _atomic_spin_unlock_irqrestore(p, flags);
74 }
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
//(1UL << (1 % 32)) <==> (1 << 1结果为2)
#define BIT_WORD(nr) ((nr) / //BITS_PER_LONG) 《==》1 / 32 = 0
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
= ((unsigned long *)addr) + 0;
= ((unsignd long *)fs4412_idev->evbit);
//*p |= mask; <==> *p = *p | mask;
//*p = fs4412_idev->evbit[0] | mask;
//*p = fs4412_idev->evbit[0] | 2;
//fs4412_idev->evbit[0] = fs4412_idev->evbit[0] | 2;
//不关心原有值是多少
//最终:1 & (dev->evbit[0] >> 1) <==> 1 & (2 >> 1) 为真
//所以if (is_event_supported(type, dev->evbit, EV_MAX))才为真。
参考代码:
1 #include <linux/module.h> 2 #include <linux/platform_device.h> 3 #include <linux/input.h> 4 #include <linux/interrupt.h> 5 #include <linux/irqreturn.h> 6 #include <linux/sched.h> 7 #include <linux/slab.h> 8 9 struct input_dev *fs4412_idev; 10 struct resource *res_key2; 11 struct resource *res_key3; 12 int flag2 = 0,flag3 = 0;//模拟按键的高低电平 13 14 irqreturn_t fs4412_inputkey_handler(int irqno,void *id) 15 { 16 #if 0 17 if(irqno == res_key2->start) 18 { 19 input_event(fs4412_idev,EV_KEY,KEY_2,2);//设置了type=,code=,value=,调用唤醒接口 20 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 21 } 22 if(irqno == res_key3->start) 23 { 24 input_event(fs4412_idev,EV_KEY,KEY_3,2); 25 input_sync(fs4412_idev); 26 } 27 #endif 28 if(irqno == res_key2->start) 29 { 30 if(flag2 == 0) 31 { 32 input_event(fs4412_idev,EV_KEY,KEY_2,1);//设置了type=,code=,value=,调用唤醒接口 33 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 34 flag2 = 1; 35 } 36 if(flag2 == 1) 37 { 38 input_event(fs4412_idev,EV_KEY,KEY_2,0);//设置了type=,code=,value=,调用唤醒接口 39 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 40 flag2 = 0; 41 } 42 } 43 if(irqno == res_key3->start) 44 { 45 if(flag3 == 0) 46 { 47 input_event(fs4412_idev,EV_KEY,KEY_3,1); 48 input_sync(fs4412_idev); 49 flag3 = 1; 50 } 51 if(flag3 == 1) 52 { 53 input_event(fs4412_idev,EV_KEY,KEY_3,0); 54 input_sync(fs4412_idev); 55 flag3 = 0; 56 } 57 } 58 59 return IRQ_HANDLED; 60 } 61 62 struct of_device_id inputkey_match_tbl[] = { 63 { 64 .compatible = "fs4412,key", 65 }, 66 {}, 67 }; 68 69 int fs4412_inputkey_probe(struct platform_device *pdev) 70 { 71 int ret; 72 printk("match ok "); 73 fs4412_idev = input_allocate_device();//申请空间 74 75 set_bit(EV_KEY,fs4412_idev->evbit); 76 set_bit(KEY_2,fs4412_idev->keybit); 77 set_bit(KEY_3,fs4412_idev->keybit); 78 79 ret = input_register_device(fs4412_idev); 80 81 res_key2 = platform_get_resource(pdev,IORESOURCE_IRQ,0); 82 res_key3 = platform_get_resource(pdev,IORESOURCE_IRQ,1); 83 ret = request_irq(res_key2->start,fs4412_inputkey_handler,IRQF_TRIGGER_FALLING,"key2",NULL); 84 ret = request_irq(res_key3->start,fs4412_inputkey_handler,IRQF_TRIGGER_FALLING,"key3",NULL); 85 return 0; 86 } 87 88 int fs4412_inputkey_remove(struct platform_device *pdev) 89 { 90 free_irq(res_key3->start,NULL); 91 free_irq(res_key2->start,NULL); 92 93 input_unregister_device(fs4412_idev); 94 kfree(fs4412_idev); 95 return 0; 96 } 97 98 struct platform_driver pdrv = { 99 .driver = { 100 .name = "inputkey", 101 .of_match_table = inputkey_match_tbl, 102 }, 103 104 .probe = fs4412_inputkey_probe, 105 .remove = fs4412_inputkey_remove, 106 }; 107 108 module_platform_driver(pdrv); 109 MODULE_LICENSE("GPL");
1 #include <linux/module.h> 2 #include <linux/platform_device.h> 3 #include <linux/input.h> 4 #include <linux/interrupt.h> 5 #include <linux/irqreturn.h> 6 #include <linux/sched.h> 7 #include <linux/slab.h> 8 9 struct input_dev *fs4412_idev; 10 struct resource *res_key2; 11 struct resource *res_key3; 12 int flag2 = 0,flag3 = 0;//模拟按键的高低电平 13 14 irqreturn_t fs4412_inputkey_handler(int irqno,void *id) 15 { 16 #if 0 17 if(irqno == res_key2->start) 18 { 19 input_event(fs4412_idev,EV_KEY,KEY_2,2);//设置了type=,code=,value=,调用唤醒接口 20 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 21 } 22 if(irqno == res_key3->start) 23 { 24 input_event(fs4412_idev,EV_KEY,KEY_3,2); 25 input_sync(fs4412_idev); 26 } 27 #endif 28 if(irqno == res_key2->start) 29 { 30 if(flag2 == 0) 31 { 32 input_event(fs4412_idev,EV_KEY,KEY_2,1);//设置了type=,code=,value=,调用唤醒接口 33 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 34 flag2 = 1; 35 } 36 if(flag2 == 1) 37 { 38 input_event(fs4412_idev,EV_KEY,KEY_2,0);//设置了type=,code=,value=,调用唤醒接口 39 input_sync(fs4412_idev);//保证type=EV_SYN,code=SYN_REPORT,为了调用唤醒接口 40 flag2 = 0; 41 } 42 } 43 if(irqno == res_key3->start) 44 { 45 if(flag3 == 0) 46 { 47 input_event(fs4412_idev,EV_KEY,KEY_3,1); 48 input_sync(fs4412_idev); 49 flag3 = 1; 50 } 51 if(flag3 == 1) 52 { 53 input_event(fs4412_idev,EV_KEY,KEY_3,0); 54 input_sync(fs4412_idev); 55 flag3 = 0; 56 } 57 } 58 59 return IRQ_HANDLED; 60 } 61 62 struct of_device_id inputkey_match_tbl[] = { 63 { 64 .compatible = "fs4412,key", 65 }, 66 {}, 67 }; 68 69 int fs4412_inputkey_probe(struct platform_device *pdev) 70 { 71 int ret; 72 printk("match ok "); 73 fs4412_idev = input_allocate_device();//申请空间 74 75 set_bit(EV_KEY,fs4412_idev->evbit); 76 set_bit(KEY_2,fs4412_idev->keybit); 77 set_bit(KEY_3,fs4412_idev->keybit); 78 79 ret = input_register_device(fs4412_idev); 80 81 res_key2 = platform_get_resource(pdev,IORESOURCE_IRQ,0); 82 res_key3 = platform_get_resource(pdev,IORESOURCE_IRQ,1); 83 ret = request_irq(res_key2->start,fs4412_inputkey_handler,IRQF_TRIGGER_FALLING,"key2",NULL); 84 ret = request_irq(res_key3->start,fs4412_inputkey_handler,IRQF_TRIGGER_FALLING,"key3",NULL); 85 return 0; 86 } 87 88 int fs4412_inputkey_remove(struct platform_device *pdev) 89 { 90 free_irq(res_key3->start,NULL); 91 free_irq(res_key2->start,NULL); 92 93 input_unregister_device(fs4412_idev); 94 kfree(fs4412_idev); 95 return 0; 96 } 97 98 struct platform_driver pdrv = { 99 .driver = { 100 .name = "inputkey", 101 .of_match_table = inputkey_match_tbl, 102 }, 103 104 .probe = fs4412_inputkey_probe, 105 .remove = fs4412_inputkey_remove, 106 }; 107 108 module_platform_driver(pdrv); 109 MODULE_LICENSE("GPL");