天天看點

Iput子系統模型探究--2(handler-->以evdev_handler為例)



3. 關于input_handler

//Evdev--> Event char devices, giving access to raw input device events.

接下來以evdev(Input driver event char devices)為例,探究基本的handler;

3.1 input_handler資料結構

struct input_handler {

 void *private;  

 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

 bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

 bool (*match)(struct input_handler *handler, struct input_dev *dev);

 int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

 void (*disconnect)(struct input_handle *handle);

 void (*start)(struct input_handle *handle);

 const struct file_operations *fops;

 int minor;

 const char *name;

 const struct input_device_id *id_table;

 struct list_head h_list;

 struct list_head node;

};

3.2 初始化evdev

static int __init evdev_init(void)

{

 return input_register_handler(&evdev_handler);

}

直接看--input_register_handler

int input_register_handler(struct input_handler *handler)

{

 struct input_dev *dev;

 int retval;

 retval = mutex_lock_interruptible(&input_mutex); //互斥通路--防止并發(連結清單也相當于資源)

 if (retval)

  return retval;

 INIT_LIST_HEAD(&handler->h_list);  //初始化h_list, 用于handle

 if (handler->fops != NULL) {

  if (input_table[handler->minor >> 5]) {

   retval = -EBUSY;

   goto out;

  }

  input_table[handler->minor >> 5] = handler; //将handler填入全局變量input_table中

 }

 list_add_tail(&handler->node, &input_handler_list); //将handler添加到input_handler_list全局handler連結清單中

 list_for_each_entry(dev, &input_dev_list, node) //周遊input_dev_list裝置連結清單,比對handler和input_device

  input_attach_handler(dev, handler); 

 input_wakeup_procfs_readers();

 out:

 mutex_unlock(&input_mutex);   //解鎖

 return retval;

}

在evdev中handler->connect=evdev_connect;

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,

    const struct input_device_id *id)

{

 struct evdev *evdev;

 int minor;

 int error;

 for (minor = 0; minor < EVDEV_MINORS; minor++)   //minor < 32

  if (!evdev_table[minor])

   break;

 if (minor == EVDEV_MINORS) {

  pr_err("no more free evdev devices\n");

  return -ENFILE;

 }

 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);

 INIT_LIST_HEAD(&evdev->client_list);  //初始化client_list-->用來連接配接用戶端client

 spin_lock_init(&evdev->client_lock);  //初始化連結清單鎖-->互斥通路client_list,防止并發

 mutex_init(&evdev->mutex);     //初始化evdev防止并發通路    

 init_waitqueue_head(&evdev->wait);   //初始化等待隊列

 dev_set_name(&evdev->dev, "event%d", minor);   //設定evdev->dev的名字-->event%d

 evdev->exist = true;      //設定evdev存在标志

 evdev->minor = minor;      //設定evdev次裝置号

 evdev->handle.dev = input_get_device(dev);   

 evdev->handle.name = dev_name(&evdev->dev); 

 evdev->handle.handler = handler;     

 evdev->handle.private = evdev;    //設定handle.private資料    

 evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); //設定evdev->dev的裝置号--主裝置号13,用于建立裝置檔案

 evdev->dev.class = &input_class;   //設定裝置類-->屬于input_class類

 evdev->dev.parent = &dev->dev;    

 evdev->dev.release = evdev_free;

 device_initialize(&evdev->dev);      //初始化裝置

 error = input_register_handle(&evdev->handle);  //注冊handle,和input_dev和handler建立連接配接 

 error = evdev_install_chrdev(evdev);   

 error = device_add(&evdev->dev);    //注冊evdev , 生成裝置檔案(event%d)

 return 0;

}

繼續閱讀