input core input.c and evdev.c (2)

9 篇文章 0 订阅

接昨天上篇:

说到了input_fops,下面接上:

input_fops:
 

   1:    /*打开操作*/
   2:      input_open_file
   3:      /*不做操作*/
   4:      noop_llseek

input_open_file:
  

   1:   /*从inode获取minor,获得handler,取得handler的fops,并执行它的open操作*/
   2:      /*根据inode获取次设备号,再由次设备号算出它在input_table中的位置*/
   3:      handler = input_table[iminor(inode) >> 5];
   4:      if (handler)
   5:          new_fops = fops_get(handler->fops); 
   6:   
   7:      old_fops = file->f_op;
   8:      file->f_op = new_fops; 
   9:   
  10:      err = new_fops->open(inode, file); 
  11:   
  12:      fops_put(old_fops);
  13:   

这里用到了handler,看handler是怎么注册的:
input_register_handler:
   

   1:  /*初始化handler的h_list*/
   2:      INIT_LIST_HEAD(&handler->h_list);
   3:      /*根据handler的minor将handler放到相应的input_table位置中*/
   4:      if (handler->fops != NULL) {
   5:          if (input_table[handler->minor >> 5]) {
   6:              retval = -EBUSY;
   7:              goto out;
   8:          }
   9:          input_table[handler->minor >> 5] = handler;
  10:      }
  11:      /*将handler通过node连接到input_handler_list链表中*/
  12:      list_add_tail(&handler->node, &input_handler_list);
  13:      /*遍历input_dev_list链表,找出与这个handler匹配的input_dev
  14:       *并和它connect,匹配和connect的操作就是input_attach_handler
  15:       *所做的事情
  16:       */
  17:      list_for_each_entry(dev, &input_dev_list, node)
  18:          input_attach_handler(dev, handler);
  19:      /*唤醒input_devices_poll_wait的等待队列*/
  20:      input_wakeup_procfs_readers();

这里说到注册handler的时候要遍历input_dev链表,那么input_dev是在哪里注册的呢?
这里当然必须提到input_dev的注册函数input_register_device,在用它注册input_dev
之前必须要分配一个input_dev并且设置它能够做的事情,这里要用input_allocate_device来分配,
用__set_bit,input_set_capability,input_set_abs_params等来设置input_dev的支持的事件evbit,
以及将所支持事件的bit数组中支持的值置相应位。这都是注册具体设备时根据设备支持的事件进行
设置了。设置完这些东西就可以注册这个input_dev了:

input_register_device:

  

   1:   /* 对每个输入设备都设置EV_SYN位 */
   2:      __set_bit(EV_SYN, dev->evbit); 
   3:   
   4:      /* 清除保留位 */
   5:      __clear_bit(KEY_RESERVED, dev->keybit); 
   6:   
   7:      /* 注册设备时没有提到evbit位,都把它们清除掉 */
   8:      input_cleanse_bitmasks(dev); 
   9:   
  10:      /*如果没有设置get_keycode[_new]/set_keycode[_new],
  11:       *则使用input.c中定义的默认方法*/
  12:      if (!dev->getkeycode && !dev->getkeycode_new)
  13:          dev->getkeycode_new = input_default_getkeycode; 
  14:   
  15:      if (!dev->setkeycode && !dev->setkeycode_new)
  16:          dev->setkeycode_new = input_default_setkeycode; 
  17:   
  18:      dev_set_name(&dev->dev, "input%ld",
  19:               (unsigned long) atomic_inc_return(&input_no) - 1);
  20:      /*增加设备,这里会干很多设备core层的事情*/
  21:      error = device_add(&dev->dev); 
  22:   
  23:      /*这里跟注册handler的时候相似,把input_dev加到input_dev_list
  24:       *链表中,然后遍历handler的链表,找到与这个input_dev匹配的handler
  25:       *再把它们connect*/
  26:      list_add_tail(&dev->node, &input_dev_list); 
  27:   
  28:      list_for_each_entry(handler, &input_handler_list, node)
  29:          input_attach_handler(dev, handler);
  30:      /*唤醒等待队列*/
  31:      input_wakeup_procfs_readers(); 
  32:   

在input_allocate_device分配input_dev的时候,给它的设备type设置为
input_dev_type,文件中一大部分代码都是为了完成这个device_type的
成员。最重要的就是input_dev_attr_groups
在proc_init的时候两个文件handlers,devices,给它们注册的文件操作符分别是
input_handlers_fileopsinput_devices_fileops,文件中也有一大部分代码
是为了完成这两个文件操作符的实现。
余下的就是input提供的接口了,就不细说了,用到的时候看看就OK,主要是要对框架了解清楚。

====================================================

我们在写驱动的时候常常会用到input_event,input_sync等,这些都是通过事件层来做的,这就需要了解evdev.c,

看看这个事件设备是怎么搞的。

evdev.c
先看最下面
evdev_init:
  

   1:   input_register_handler(&evdev_handler)

注册了一个input_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:  };

name不用多说,EVDEV_MINOR_BASE是64,按照minor >> 5的算法,它应该把这个handler指针放到
input_table[1]中,evdev_ids是input_device_id数组,在input_match_device,也就是input_attach_handler
中调用的用来匹配input_dev和handler的函数中用来进行匹配,根据id->flags还有handler里的那些*bit和dev->id
的相应成员进行匹配,这里evdev_ids中,只设置了driver_info,根据匹配函数,它是跟所有的device都匹配的,
It's a bitch.......
整个evdev.c实际上就是实现这个input_handler的各个具体操作函数。
evdev_connect:
    对evdev进行初始化,从evdev_table中找出第一个没有被用过的minor,做为它的minor
    初始化它的handle成员的dev和handler,初始化它的dev成员。
    然后调用input_register_handle,注册handle,它把handle的d_node加到input_dev的
    h_list链表,把h_node加到handler的h_list链表,这样就把这个handle同时跟input_dev和
    handler关联起来。evdev_install_chrdev把初始化好的这个evdev加到evdev_table中,最后
    调用device_add增加这个evdev设备。connect大功告成。
evdev_disconnect:
    不用解释。反向操作。
evdev_event:
    把input事件发给所有的client.

了解了框架再去看具体操作的核心代码就不会迷糊了。
高万龙(冷月X)
2011.4.8

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值