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