输入子系统学习的总结
从input.c 里面的input_init函数看起
{
注册了一类设备(输入类设备)
class_register(&input_class)
申请设备号
register_chrdev(INPUT_MAJOR, "input", &input_fops);
}
问题:为什么没有在类下注册具体的设备?
因为这时候不知道会有什么具体的设备,所以猜想是在具体设备
被发现的时候才注册具体的设备
查看 input_fops,它是一个file_operations结构体,里面只有成员
.open = input_open_file,再次进去查看input_open_file(inode,file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5];
根据你的inode结构体成员算出次设备号,以此为下标取出input_table
成员赋值。
new_fops = fops_get(handler->fops)
file->f_op = new_fops;
最终将file里面的fops指向了handler里面的fops
new_fops->open(inode, file);
然后调用open函数
}
————————————————————————————————————————————————————————————————
从驱动程序的角度看看函数是怎么运行的。
在 buttons_init ()函数中有
{
buttons_dev=input_allocate_device()
{
这个函数做的是为开辟一个input_dev结构体并返回 ,
其中有dev->cdev.class = &input_class;标明自己属于
自己是输入类设备。
初始化了链表结构h_list 和node
}
input_register_device(buttons_dev);
注册设备,向谁注册呢?应该是向输入子系统注册。
{
函数里面有list_add_tail(&dev->node, &input_dev_list);
这个宏是向input_dev_list链表里面添加一个节点,也就是表明了
自己这个设备可以被发现了。
class_device_add(&dev->cdev);
这里就对应了上面的在类下注册具体的设备
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
这个宏做的应该是便利input_handler_list里面的成员,看看有没有
dev和handler匹配的项。
}
}
问题:input_handler_list是什么,谁初始化的?
handler是什么?
为什么要做匹配?
匹配的到底是在做什么?
——————————————————————————————————————————————————————————————————
硬件设备要进行输入输出的话必须对应匹配的软件驱动,既然硬件都是
自己input_register_device()向上注册的,那么软件驱动肯定也是这样的。
查看Evdev.c Joydev.c Mousedev.c里面的函数就能发现,都调用了
input_register_handler(struct input_handler *handler)
{
INIT_LIST_HEAD(&handler->h_list)
初始化了一个链表h_list,和上面的那个h_list不是同一个。
input_table[handler->minor >> 5] = handler
按照次设备号构造input_table成员。
list_add_tail(&handler->node, &input_handler_list)
往input_handler_list链表中添加一个节点
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
}
——————————————————————————————————————————————————————————————————
现在在回看上面的问题:
input_handler_list是一个链表,由各种驱动往里面添加成员,
成员结构为list_head,其实是handler大结构体里面的成员。
说白了就是把input_register_handler函数的参数handler串起来。
handler 是一个input_handler结构,里面含有file_operations成员
这样就能把通用的框架转为具体的驱动实现了。
list_for_each_entry()其实是一个宏,进去看看就是for循环
{
input_attach_handler(dev,handler)
{
input_match_device(handler->id_table, dev)
查看handler的id_table和dev是不是匹配,是的话调用
下面的函数
handler->connect(handler, dev, id)
}
}
问题:input_match_device()是怎么判断匹配的?
connect()里面做了什么?
id_table是struct input_device_id结构,判断里面的成员
和dev结构里面的id里面的成员,一致的话返回id值
connect()函数的调用实际上对应了每个不同handler里面的fops
下的connect函数。
{
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
开辟空间存放evdev结构
。。。。。
然后各种初始化,其实就是让dev知道谁是它的handler,
让handler知道谁是它的dev
evdev_table[minor] = evdev;
把evdev结构放进数组里面
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor)
创建设备节点
class_device_create(&input_class, &dev->cdev, devt,
dev->cdev.dev, evdev->name);
创建好类下的设备
input_register_handle(&evdev->handle)
让输入子系统知道存在这么一个handler
}