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;  /*私有數據*/

 /*@event: event handler. This method is being called by input core with
  * interrupts disabled and dev->event_lock spinlock held and so
  * it may not sleep
  */
 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 /*
 * @filter: similar to @event; separates normal event handlers from
  *"filters".*/
 bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 
 /** @match: called after comparing device's id with handler's id_table
 * to perform fine-grained matching between device and handler
  */
 bool (*match)(struct input_handler *handler, struct input_dev *dev);
 
 /* * @connect: called when attaching a handler to an input device*/
 int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
 
 /* * @disconnect: disconnects a handler from input device*/
 void (*disconnect)(struct input_handle *handle);
 /*
  * @start: starts handler for given handle. This function is called by
  * input core right after connect() method and also when a process
  * that "grabbed" a device releases it*/
 void (*start)(struct input_handle *handle);

 /* @fops: file operations this driver implements*/
 const struct file_operations *fops;
 
 /** @minor: beginning of range of 32 minors for devices this driver
  **can provide*/
 int minor;
 
 /*@name: name of the handler, to be shown in /proc/bus/input/handlers*/
 const char *name;
 
 /* * @id_table: pointer to a table of input_device_ids this driver can
 * handle,匹配的時候用*/
 const struct input_device_id *id_table;
 
 /** @h_list: list of input handles associated with the handler*/
 struct list_head h_list;
 
 /*@node: for placing the driver onto input_handler_list*/
 struct list_head node;
};


3.2 初始化evdev
static int __init evdev_init(void)
{
 return input_register_handler(&evdev_handler);
}

直接看--input_register_handler
/**
 * input_register_handler - register a new input handler
 * @handler: handler to be registered
 *
 * This function registers a new input handler (interface) for input
 * devices in the system
 
 **and attaches it to all input devices that are compatible with the 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鏈表中

 /**input_attach_handler這個函數在註冊input_dev設備時調用到,在註冊input_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;
}


/******************接下來分析****handler->connect**************************/
在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;

 /*查找全局evdev_table中可用的號碼*/
 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*/
 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次設備號

 /*將handler驅動 和 input_dev設備用handle連接起來*/
 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;
 
 /********前面Linux驅動模型探究--3(device)*************/
 
 device_initialize(&evdev->dev);      //初始化設備

  /*input_register_handle - register a new input handle
   *handle: handle to register*/
 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章