linux kernel input 子系统分析Word格式.docx
《linux kernel input 子系统分析Word格式.docx》由会员分享,可在线阅读,更多相关《linux kernel input 子系统分析Word格式.docx(41页珍藏版)》请在冰豆网上搜索。
25
26
27irqreturn_tdo_irq(intirqno,void*data)
28{
29//事件上报
30//算出第几个按键
31intkeynum=irqno-IRQ_EINT(26);
//0-3
32unsignedintval;
33
34val=ioread32(gpxconf+1);
35val=val>
>
2;
36
37//printk("
keynum:
%dval:
%#x\n"
keynum,val);
38switch(keynum)
39{//事件上报函数.
40case0:
input_report_key(device,KEY_A,!
(val&
(1<
<
keynum)));
break;
41case1:
input_report_key(device,KEY_B,!
42case2:
input_report_key(device,KEY_C,!
43case3:
input_report_key(device,KEY_D,!
44}
45
46//同步
47input_sync(device);
48
49returnIRQ_HANDLED;
50}
51
52
53//*************************************************
54//模块入口出口
55
56staticint__inittest_init(void)
57{
58intret;
59inti;
60
61for(i=0;
i<
ARRAY_SIZE(irqs);
i++)
62{//请求中断
63ret=request_irq(irqs[i],do_irq,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING|IRQF_SHARED,"
myirq"
(void*)88);
64if(ret<
0)
65{gotoErr;
66}
67}
68//分配一个事件上报设备结构体
69device=input_allocate_device();
70if(IS_ERR(device))
71{
72ret=PTR_ERR(device);
73gotoErr1;
74}
75
76//#defineBITS_PER_LONG32
77//#defineBIT_MASK(nr)(1UL<
((nr)%BITS_PER_LONG))
78//#defineBIT_WORD(nr)((nr)/BITS_PER_LONG)
79
80device->
evbit[BIT_WORD(EV_KEY)]|=BIT_MASK(EV_KEY);
//使能按键事件类型
81device->
keybit[BIT_WORD(KEY_A)]|=BIT_MASK(KEY_A);
//使能按键值为A的事件
82device->
keybit[BIT_WORD(KEY_B)]|=BIT_MASK(KEY_B);
83device->
keybit[BIT_WORD(KEY_C)]|=BIT_MASK(KEY_C);
84device->
keybit[BIT_WORD(KEY_D)]|=BIT_MASK(KEY_D);
85
86
87//注册一个input设备上报类型上报键值
88ret=input_register_device(device);
89if(ret<
90{
91gotoErr2;
92}
93
94//硬件初始化
95HardWare_init();
96
97returnret;
98
99Err2:
100input_free_device(device);
101Err1:
102Err:
103while(--i)
104{
105free_irq(irqs[i],(void*)88);
106}
107
108returnret;
109}
110
111staticvoid__exittest_exit(void)
112{
113inti;
114
115input_unregister_device(device);
116
117input_free_device(device);
118
119for(i=0;
120{
121free_irq(irqs[i],(void*)88);
122}
123
124HardWare_exit();
125}
126
127module_init(test_init);
128module_exit(test_exit);
129
130MODULE_LICENSE("
GPL"
);
先对他的一个主体流程进行分析一下
代码分析:
模块入口函数为test_init
它首先去申请了4个按键的中断,双边缘触发.
而后,它分配一个事件上报结构体的空间,并对其进行赋值:
1staticstructinput_dev*device=NULL;
1//分配一个事件上报设备结构体
2device=input_allocate_device();
1device->
2device->
3device->
4device->
5device->
//使能按键值为A的事件
这个结构体的原型是这样的:
1structinput_dev{
2constchar*name;
//设备名字
3constchar*phys;
//设备在系统中的物理路径
4constchar*uniq;
//设备的唯一标识码
5structinput_idid;
//设备id,包含总线id,厂商id,与input_handler匹配的时会用到
7unsignedlongpropbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
//设备性质
8
9unsignedlongevbit[BITS_TO_LONGS(EV_CNT)];
//设备支持的事件类型
10unsignedlongkeybit[BITS_TO_LONGS(KEY_CNT)];
//支持的具体的按键。
按钮事件
11unsignedlongrelbit[BITS_TO_LONGS(REL_CNT)];
//支持的具体的相对坐标事件
12unsignedlongabsbit[BITS_TO_LONGS(ABS_CNT)];
//支持的具体的绝对坐标事件
13unsignedlongmscbit[BITS_TO_LONGS(MSC_CNT)];
//支持的具体的混杂事件
14unsignedlongledbit[BITS_TO_LONGS(LED_CNT)];
//支持的具体的led指示灯事件
15unsignedlongsndbit[BITS_TO_LONGS(SND_CNT)];
//支持的具体的音效事件unsignedlongffbit[BITS_TO_LONGS(FF_CNT)];
//支持的具体的力反馈事件
16unsignedlongswbit[BITS_TO_LONGS(SW_CNT)];
//支持的具体的开关事件
17
18unsignedinthint_events_per_packet;
19
20unsignedintkeycodemax;
//键盘码表的大小
21unsignedintkeycodesize;
//键盘码中的元素个数
22void*keycode;
//设备的键盘码表
23/*两个可选方法,用于配置和获取键盘码表*/
24int(*setkeycode)(structinput_dev*dev,
25conststructinput_keymap_entry*ke,
26unsignedint*old_keycode);
27int(*getkeycode)(structinput_dev*dev,
28structinput_keymap_entry*ke);
29
30structff_device*ff;
/*如果设备支持力反馈,则该成员将指向力反馈的设备描述
31结构*/
32
33unsignedintrepeat_key;
/*保存上一个键值,实现软件自动重复按键*/
34structtimer_listtimer;
/*用于软件自动重复按键的定时器*/
35
36intrep[REP_CNT];
37
38structinput_mt_slot*mt;
39intmtsize;
40intslot;
41inttrkid;
42
43structinput_absinfo*absinfo;
44
45unsignedlongkey[BITS_TO_LONGS(KEY_CNT)];
//反映设备按键按钮的当前状态
46unsignedlongled[BITS_TO_LONGS(LED_CNT)];
//反映设备led灯的当前状态
47unsignedlongsnd[BITS_TO_LONGS(SND_CNT)];
//反映设备音效的当前状态
48unsignedlongsw[BITS_TO_LONGS(SW_CNT)];
//反映设备开关的当前状态
49
50/*提供以下4个设备驱动层的操作接口,根据具体的设备需求实现他们*/
51int(*open)(structinput_dev*dev);
//将在input_open_device()中调用
52void(*close)(structinput_dev*dev);
//将在input_close_device()中调用
53int(*flush)(structinput_dev*dev,structfile*file);
55/*(event)用于处理送到设备驱动层来的事件,很多事件在事件处理层被处理,但有很多事件仍需
56要送到设备驱动中,如led指示灯事件和音效事件,因为这些操作通常需要设备驱动执行*/
57int(*event)(structinput_dev*dev,unsignedinttype,unsignedintcode,intvalue);
58
59structinput_handle__rcu*grab;
60
61spinlock_tevent_lock;
62structmutexmutex;
63
64/*记录输入事件处理程序(inputhandlers)调用设备open()方法的次数,保证设备open()是在第一个调用input_open_device()中被调用,设备close()方法是在最后一次调用input_close_device()中被调用*/
65unsignedintusers;
66boolgoing_away;
67
68boolsync;
//上次同步事件(EV_SYNC)发生后没有新事件产生,则被设置为1*/
69
70structdevicedev;
//内嵌设备device结构
71structlist_headh_list;
//与该设备相关的输入句柄(inputhandles)列表
72structlist_headnode;
//通过该成员,系统中的所有的input_dev对象被管理
73};
上面是我做的一些注释.
而且在上面的按键设备的驱动中,我还对evbit
和keybit
两个数值进行赋值.
它那个宏定义是这样的:
1//#defineBITS_PER_LONG32
2//#defineBIT_MASK(nr)(1UL<
3//#defineBIT_WORD(nr)((nr)/BITS_PER_LONG)
这里边所支持的事件类型和支持的具体的按键按钮类型是这样的:
1#defineEV_SYN0x00
2#defineEV_KEY0x01
3#defineEV_REL0x02
4#defineEV_ABS0x03
5#defineEV_MSC0x04
6#defineEV_SW0x05
7#defineEV_LED0x11
8#defineEV_SND0x12
9#defineEV_REP0x14
9#defineEV_FF0x15
10#defineEV_PWR0x16
11#defineEV_FF_STATUS0x17
12#defineEV_MAX0x1f
12#defineEV_CNT(EV_MAX+1)
所支持的按键按钮类型就比较多了
1
2#defineKEY_RESERVED0
3#defineKEY_ESC1
4#defineKEY_12
5#defineKEY_23
6#defineKEY_34
7#defineKEY_45
8#defineKEY_56
9#defineKEY_67
10#defineKEY_78
11#defineKEY_89
12#defineKEY_910
13#defineKEY_011
14......
这些相对应的类型都是用一些宏定义来定义,到上报个核心层再上报到事件处理层的时候以一个结构体的形式的数据体现给用户,后面会讲到这个结构体
回到源代码:
然后就是注册一个input设备把刚才赋值的事件上报类型传进去:
1//注册一个input设备上报类型上报键值
2ret=input_register_device(device);
3if(ret<
4{
5gotoErr2;
6}
后面的硬件初始化就是对gpio口的配置而已,这里涉及到硬件原理图上的东西,其实就是做了一个寄存器地址的映射
在中断函数内
1irqreturn_tdo_irq(intirqno,void*data)
2{
3//事件上报
4//算出第几个按键
5intkeynum=irqno-IRQ_EINT(26);
6unsignedintval;
7
8val=ioread32(gpxconf+1);
9val=val>
10
11//printk("
12switch(keynum)
13{
14case0:
15case1:
16case2:
17case3:
18}
20//同步
21input_sync(device);
22
23returnIRQ_HANDLED;
24}
25
其实总的来说我们做了两个事情,第一个就是触发中断后,我们上报了是第几个按键触发的中断,并进行同步处理.
现在,我已经把这个最简单的一个按键事件上报驱动讲解了一遍
其实我们有很多疑问:
第一个就是:
我们怎么分配的一个事件上报结构体
第二个问题,我们是怎么将事件层层上报,将inputdriver,inputcore,inputhandler这三层联系起来的.
第三个问题,我们给上层提供的是一个怎么样的借口,给上层上报的是一个怎么的数据.
其实第一个问题比较简单,
我只是为了拿出来缓解一下当前比较紧张的气氛,透露一下,第二个问题才是关键!
第一个问题它只是做了一个分配空间并对其初始化值的操作:
1*///申请一个新的inputdevice
2structinput_dev*input_allocate_device(void)
3{
4structinput_dev*dev;
6dev=kzalloc(sizeof(structinput_dev),GFP_KERNEL);
7if(dev){
8dev->
dev.type=&
input_dev_type;
9dev->
dev.class=&
input_class;
10device_initialize(&
dev->
dev);
11mutex_init(&
mutex);
12spin_lock_init(&
event_lock);
13INIT_LIST_HEAD(&
h_list);
14INIT_LIST_HEAD(&
node);
15
16__module_get(THIS_MODULE);
17}
18
19returndev;
20}
21EXPORT_SYMBOL(input_allocate_device);
是不是觉得自己竟然能两眼就能看懂这些代码,别惊讶,其实你自己挺强的,就连我都要花喵一眼的时间去看才能看懂它
下面才是重头戏:
inputcore
代码.
在前面的驱动当中,我们在分配完input_dev结构体后,我们直接在没有产生并触发按键中断之前,抢先注册了一个input设备
其实如果按照标准的写法
我们注册一个input