韦东山驱动视频笔记——5.输入子系统概念介绍

输入子系统的核心代码在/driver/input/input.c,先看入口函数input_init(),在这里调用了register_chrdev(INPUT_MAJOR, "input", &input_fops);内核帮我们做了注册设备号的工作,发现在结构体input_fops里只定义了open函数,像read,write等函数都没有定义,进入这个open函数去看看有什么内容:

input_open_file()  
    struct input_handler *handler  
    handler = input_table[iminor(inode) >> 5]  
    new_fops = fops_get(handler->fops)  
    file->f_op = new_fops  
    new_fops->open(inode, file)  

现在最根本的是要弄清楚handler是怎么来的,因为input_table是个静态变量,所以在本文件里经过查找发现是在函数input_register_handler()里给它赋值

input_register_handler()  
    input_table[handler->minor >> 5] = handler;  
    list_add_tail(&handler->node, &input_handler_list);//把handler放入链表以便以后查询  
    list_for_each_entry(dev, &input_dev_list, node)//循环查看input_dev_list链表  
    input_attach_handler(dev, handler);            //看看有没有支持这个handler的设备  
input_attach_handler()  
    const struct input_device_id *id;  
    id = input_match_device(handler->id_table, dev);//通过比较设备和handler的idtable来决定是否匹配  
    handler->connect(handler, dev, id);             //若匹配则调用connect函数 

这个connect是什么意思,那就要看注册handler时传进来的参数,经过查找input_register_handler发现有很多地方调用,下面就选取一个(/drivers/char/evdev.c)来说明:

在函数evdev_init()里:input_register_handler(&evdev_handler);

1 static struct input_handler evdev_handler = {  
2     .event      = evdev_event,  
3     .connect    = evdev_connect,  
4     .disconnect = evdev_disconnect,  
5     .fops       = &evdev_fops,  
6     .minor      = EVDEV_MINOR_BASE,  
7     .name       = "evdev",  
8     .id_table   = evdev_ids,  
9 };  

所以上面的connect函数就是指的这里的evdev_connect函数

evdev_event()  
    evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);  
    evdev->handle.dev = input_get_device(dev);  
     evdev->handle.name = evdev->name;  
    evdev->handle.handler = handler;  
    evdev->handle.private = evdev;  
    error = input_register_handle(&evdev->handle);  

可以看出,通过handle把设备和handler联系起来,然后注册handle

input_register_handle()  
    struct input_handler *handler = handle->handler;  
    struct input_dev *dev = handle->dev;  
    list_add_tail_rcu(&handle->d_node, &dev->h_list);  
    list_add_tail(&handle->h_node, &handler->h_list);

这时候把handle放到设备的一个链表中,也放到handler的一个链表中,这样才真正联系起来(设备dev通过查找h_list可以找到支持该设备的所有handler,handler通过查找h_list可以找到支持该handler的所有设备)

假如现在应用程序调用read,那么对应我们驱动里应该是evdev_handler->fops->read 即evdev_read

evdev_read()  
        if (client->head == client->tail && evdev->exist &&  
        (file->f_flags & O_NONBLOCK))  
        return -EAGAIN;  
  
    retval = wait_event_interruptible(evdev->wait,  
        client->head != client->tail || !evdev->exist);

这里读为非阻塞时立刻返回,若是阻塞就休眠,和之前自己写的read函数很类似,谁来唤醒呢?经过搜索发现是在evdev_event唤醒的

evdev_event()  
    struct evdev *evdev = handle->private;  
    wake_up_interruptible(&evdev->wait);  

evdev_event被input_dev那层调用的,在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数,看看input_event函数

input_event()  
    input_handle_event()  
        input_pass_event()  
            handle->handler->event(handle,type, code, value);   即evdev_event 

 

转载于:https://www.cnblogs.com/linux-rookie/p/3245427.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值