/////////////////////////////////////////////////////////////////////
总结:三层
我们写的驱动层
我们写的案例:中断方式按键中断
gpio_request申请gpio,因为按键与gpio有关
s3c_gpio_cfgpin设置gpio模式为中断模式
gpio_get_value读取引脚的值,注意读取引脚的值要将gpio设为输入或输出模式读取,好点
request_irq申请中断号并绑定中断程序和设置中断触发情况
中断号都在irqs.h文件中
flag设置中断触发情况可以si搜到
在绑定的中断程序中发送input结构体input_report_key,向上汇报硬件触发事件
input_allocate_device申请input结构体的内存
set_bit设置允许向上汇报的事件类型
input_register_device注册input设备
九鼎移植的button_x210.c驱动层轮询方式
从module_init开始
module_init
s3c_button_init
platform_device_register 完成平台总线的设备和驱动注册,就是将我们这个设备放到平台
platform_driver_register 总线上去管理,即当设备和驱动相遇会调用pore函数
.probe = s3c_button_probe,
s3c_button_probe
gpio_request 向gpiolib申请gpio
s3c_gpio_setpull 设置上下拉
s3c_gpio_cfgpin 设置成输入模式,则表示用轮询方式
s3c_button_history[]记录以前引脚的值,因为我们采用轮询方式,如果采集的数据与上次一样我们就不进行处理
input_allocate_device 申请内存
set_bit(EV_KEY, input->evbit);设置该驱动支持向上汇报硬件触发事件的类型
set_bit(s3c_Keycode[i], input->keybit);设置该类型的具体事件,就一个对应type一个core
input_register_device 注册
init_timer定时,定轮询时间,因为定时是单次定时,因此我们要在每次定时绑定的处理函数结束前把定时更新。
timer.function = s3cbutton_timer_handler;绑定定时函数
timer.expires = jiffies + (HZ/100);HZ是一个值表示在内核里面的1s。分成100,就是10ms
add_timer(&timer);//添加计时
绑定的定时函数
s3cbutton_timer_handler
gpio_get_value获取值
input_report_key要与之前的值对比一下再向上汇报
mod_timer更新定时
/////////////////////////////////////////////////////////////////////
核心层input.c
subsys_initcall同样从这里开始,定义为一个模块,满足linux的可裁剪性
input_init
class_register//在sys下注册一个input类
input_proc_init//在proc下添加一个接口
register_chrdev//在/dev下注册一个设备文件夹吧,只支持open,那些次input设备就在下面
对下面驱动层提高的接口为
input_allocate_device
input_set_capability
input_register_device
解析
input_allocate_device 返回的就是申请好的内存地址,然后驱动层不用定义该结构体变量只用定义指针即可
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);就是为input_dev结构体分配内存
还进行一些input设备共有的属性的初始化
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
内部其实就是一些__set_bit。
input_register_device
还进行一些input设备共同信息设置
device_add 设备添加这个就是对应的dev/input下的设备节点
list_add_tail将注册好的设备放到管理输入设备的链表里
list_for_each_entry(handler, &input_handler_list, node),input_attach_handler输入事件handler也是用链表绑定的,然后遍历并比对找出能够绑定的,就是将设备和已经注册了的handle进行匹配
input_match_device进行配对
handler->connect(handler, dev, id);handler规定的连接方法进行连接绑定
对上面输入事件驱动层提供的接口为
input_register_handler 对应写上层输入事件驱动的人调用注册的如evdev.c和mousedev.c和joydev.c属于这一层
input_register_handle handle结构体就是绑定好的设备和handler进行绑定用链表链接
解析
input_register_handler
input_table[handler->minor >> 5] = handler;
input_table是用来管理所有的handler的只能支持8个,
handler->minor都会赋值一个该handler支持的设备的次设备号的基准在除以32,表示一个hander
最多支持32个设备,每个handler都对应一个基准次设备号
list_add_tail(&handler->node, &input_handler_list);
内核中handler使用链表管理的,将注册好的设备添加到该链表中
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
同样添加一个handler就要把以前注册过的设备进行遍历看看有哪些可以与该handler进行绑定
input_register_handle
struct input_handle {handle是这种类型的
void *private;
int open;
const char *name;
//对应设备和handler的绑定。
struct input_dev *dev;
struct input_handler *handler;
//对应的链表
struct list_head d_node;
struct list_head h_node;
};
/////////////////////////////////////////////////////////////////////
输入事件驱动层,就是注册handler的,我们以evdevhandler为例,在evdev.c文件
module_init模块
evdev_init
input_register_handler(&evdev_handler);直接注册,然后就没了,我们主要研究该结构体
static struct input_handler evdev_handler = {
.event = evdev_event, //关键;给应用层返回一个event结构体
.connect = evdev_connect, //handler和设备连接的函数
.disconnect = evdev_disconnect,
.fops = &evdev_fops, //对用应用层操作设备文件时的函数的接口open,read
.minor = EVDEV_MINOR_BASE,//对应该handler支持的设备的次设备号的基准号,一个handler最大支持32个
.name = "evdev",
.id_table = evdev_ids, //对对应的handler所支持的设备的特征数组,这里没有,表示所有设备都支持
};
我们分析;event, fops, id_table
evdev_event
因为已经确定handler,则先进行一些该handler有的初始化
rcu_dereference看该信息是传给一个handler直接调用发送还是有多个handler遍历要发送的hander发送
evdev_pass_event向上层发送
client->buffer[client->head++] = *event;将信息从内核发送到应用层
wake_lock_timeout还要进行一些解锁,唤醒的堵塞的read
.read = evdev_read,
if (count < input_event_size())return -EINVAL;保证传参正确
wait_event_interruptible read堵塞就堵塞在这里,唤醒在evdev_event这里的
input_event_to_user //将数据放到应用层去。
.id_table = evdev_ids,//对对应的handler所支持的设备的特征数组,这里没有,表示所有设备都支持
//因为eventhandle是配对所有设备的,
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
嵌入式之input驱动框架源码分析
最新推荐文章于 2022-04-18 22:25:44 发布