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

接昨天上篇:

说到了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

 

 

 

 

 

 

你可能感兴趣的:(input)