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;
}