Linux内核(十四)Input 子系统详解 IV —— 配对的input设备与input事件处理器 input_register_handle


本文章中与input子系统相关的结构体可参考input子系统结构体解析
input函数路径:drivers/input/input.c

input_handle结构体详解

input_handle结构体属于核心层,代表一个配对的input设备与input事件处理器。

int input_register_handle(struct input_handle *handle)
{
    struct input_handler *handler = handle->handler;
    struct input_dev *dev = handle->dev;
    int error;
    
    /* 获取互斥锁 */
    error = mutex_lock_interruptible(&dev->mutex);
    if (error)
        return error;

    /* 将handle的d_node,链接到其相关的input_dev的h_list链表中  */
    if (handler->filter)
        list_add_rcu(&handle->d_node, &dev->h_list);
    else
        list_add_tail_rcu(&handle->d_node, &dev->h_list);
        
    /* 释放锁 */
    mutex_unlock(&dev->mutex);
    
    /* 将handle的h_node,链接到其相关的input_handler的h_list链表中 */
    list_add_tail_rcu(&handle->h_node, &handler->h_list);

    if (handler->start)
        handler->start(handle);

    return 0;
}
EXPORT_SYMBOL(input_register_handle);

配对的input设备与input事件处理器实例

当 input设备注册Input_register_device 和 一个新的input事件注册input_register_handler 匹配上,都会调用回调函数handler->connect(handler, dev, id)

以事件处理器evdev为例:

/* drivers/input/evdev.c */
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
             const struct input_device_id *id)
{
     struct evdev *evdev;
     int minor;
     int dev_no;
     int error;
     /* 获取次设备号,从evdev_table中找到一个未使用的最小的数组项,最大值32 */
     minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
     if (minor < 0) {
          error = minor;
          pr_err("failed to reserve new minor: %d\n", error);
          return error;
     }
    /* 分配空间 */
     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
     if (!evdev) {
          error = -ENOMEM;
          goto err_free_minor;
     }
     /* 初始化client_list链表头,代表多少应用读写这个设备 */
     INIT_LIST_HEAD(&evdev->client_list);    
     spin_lock_init(&evdev->client_lock);  /* 加锁 */ 
     mutex_init(&evdev->mutex);  /*  */
     init_waitqueue_head(&evdev->wait);  /* 初始化等待队列,当evdev没有数据可读时,就 在 该队列上睡眠 */
     evdev->exist = true;  /* 设备存在 */
    
     dev_no = minor;
    
     if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
          dev_no -= EVDEV_MINOR_BASE;
     dev_set_name(&evdev->dev, "event%d", dev_no);  /* 设置设备名为eventX */
    
     evdev->handle.dev = input_get_device(dev);  /* 获取设备 */
     evdev->handle.name = dev_name(&evdev->dev);  /* 设备名称 */
     evdev->handle.handler = handler;  /* handler绑定 */  
     evdev->handle.private = evdev;  /* evdev数据指向 */
    
     evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);  /* sysfs下的设备号 */
     evdev->dev.class = &input_class;  /* 将input_class作为设备类 */
     evdev->dev.parent = &dev->dev;  /* input_dev作为evdev的父设备 */
     evdev->dev.release = evdev_free;  /* 释放函数 */
     device_initialize(&evdev->dev);  /* 初始化设备 */
            /* 注册一个handle处理事件 */
     error = input_register_handle(&evdev->handle);    
     if (error)
          goto err_free_evdev;
    
     cdev_init(&evdev->cdev, &evdev_fops);  /* 字符设备初始化 */
    
     error = cdev_device_add(&evdev->cdev, &evdev->dev);  /* 添加字符设备 */
     if (error)
          goto err_cleanup_evdev;
    
     return 0;

err_cleanup_evdev:
    evdev_cleanup(evdev);
err_unregister_handle:
    input_unregister_handle(&evdev->handle);
err_free_evdev:
    put_device(&evdev->dev);
err_free_minor:
    input_free_minor(minor);
    return error;
}

(1)保存驱动设备名字,event0是表示input子系统,驱动名字就由event1、event2…递增
(2)保存驱动设备的主次设备号,其中主设备号INPUT_MAJOR=13,次设备号=EVSEV_MINOR_BASE+驱动程序本身设备号。
(3)会在/sys/class/input类下创建驱动设备event%d,比如键盘驱动event1
(4)最终进入input_register_handler()函数来注册handle。


input核心层对驱动层和事件层之间的框架建立流程图

在这里插入图片描述
input核心层对驱动层和事件层之间的框架建立流程图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bazinga bingo

您的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值