input子系统框架代码分析:
*****************************************************************************
* ls /dev/event* 或者 /dev/input* 用户在应用程序中可以操作的文件
* ls /sys/class/input/event* 用户可以查看对应的event具体是什么事件
* ***************************************************************************
* input handler层: evdev.c
* module_init(evdev_init);
* module_exit(evdev_exit);
*
* static struct input_handler evdev_handler = {
* .event = evdev_event,
* .events = evdev_events,
* .connect = evdev_connect,
* .disconnect = evdev_disconnect,
* .legacy_minors = true,
* .minor = EVDEV_MINOR_BASE,
* .name = "evdev",
* .id_table = evdev_ids,
* };
*
* evdev_init(void)------>
* input_register_handler(&evdev_handler);------>
*
*
* INIT_LIST_HEAD(&handler->h_list);
*
*
* list_add_tail(&handler->node,&input_handler_list);
*
*
* list_for_each_entry(dev, &input_dev_list, node)
* input_attach_handler(dev, handler); -------->
*
*
* id = input_match_device(handler, dev);
*
*
*
* error = handler->connect(handler, dev, id);
*
*
* input_wakeup_procfs_readers();
*
* 总结:
* 注册了evdev_handler,遍历input_dev_list并进行匹配,且会恒匹配成功
* 自动调用handler中的connect方法-----evdev_connect
*
* ***************************************************************************
* evdev_connect()函数分析:属于input handler层
* static int evdev_connect(struct input_handler *handler,
* struct input_dev *dev,const struct input_device_id *id)
*
*
* minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
*
*
* evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
*
* INIT_LIST_HEAD(&evdev->client_list);
* spin_lock_init(&evdev->client_lock);
* mutex_init(&evdev->mutex);
*
* init_waitqueue_head(&evdev->wait);
* evdev->exist = true;
*
* dev_no = minor;
* dev_no -= EVDEV_MINOR_BASE;
*
*
* dev_set_name(&evdev->dev, "event%d", dev_no);
* evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
* evdev->dev.class = &input_class;
* evdev->dev.parent = &dev->dev;
* evdev->dev.release = evdev_free;
* device_initialize(&evdev->dev);
* device_add(&evdev->dev);
*
*
*
* evdev->handle.dev = input_get_device(dev);
* evdev->handle.name = dev_name(&evdev->dev);
* evdev->handle.handler = handler;
* evdev->handle.private = evdev;
*
*
* error = input_register_handle(&evdev->handle);
* list_add_tail_rcu(&handle->d_node, &dev->h_list);
* list_add_tail_rcu(&handle->h_node, &handler->h_list);
*
* cdev_init(&evdev->cdev, &evdev_fops);
* evdev->cdev.kobj.parent = &evdev->dev.kobj;
* error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
* 总结:
* 1.分配edev并初始化,记录input device和handler的关系
* 2.创建设备节点/dev/event0
* 3.注册cdev,并实现fops
* 4.关系:
* 多个input device可以对应一个event handler
* 一个input device对应一个evdev,对应于一个设备节点/dev/event0,1,2
* 5.所有设备节点都调用了open,read,write文件接口时
* 实际是调用了cdev中的fops中各个接口,最终调用了结构体evdev_ops
* ****************************************************************************
* input core层:input.c
*
* input_init()
* subsys_initcall(input_init);
* module_exit(input_exit);
*
*
* err = class_register(&input_class);
*
* err = input_proc_init();
*
* err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
* INPUT_MAX_CHAR_DEVICES, "input");
*
* 总结:
* 注册了主设备号,注册了input_class类
* ***************************************************************************
* input device层:自己写的代码simple_input.c
*
* ret=input_register_device(inputdev);
*
* list_add_tail(&dev->node,&input_dev_list);
*
*
* list_for_each_entry(handler, &input_handler_list, node)
* input_attach_handler(dev, handler);
*
*
* error = handler->connect(handler, dev, id);
* **************************************************************************
* 应用程序调用open函数时候实际调用的是evedv_open
*
* evedv_open函数分析:
* static int evdev_open(struct inode *inode, struct file *file)
* {
*
* struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
*
* unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
*
* unsigned int size = sizeof(struct evdev_client) +
* bufsize * sizeof(struct input_event);
*
* struct evdev_client *client;
* int error;
*
* client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
* if (!client)
* client = vzalloc(size);
* if (!client)
* return -ENOMEM;
*
*
* client->bufsize = bufsize;
* spin_lock_init(&client->buffer_lock);
*
* client->evdev = evdev;
*
* evdev_attach_client(evdev, client);
*
* error = evdev_open_device(evdev);
* if (error)
* goto err_free_client;
*
*
* file->private_data = client;
* nonseekable_open(inode, file);
*
* return 0;
*
* err_free_client:
* evdev_detach_client(evdev, client);
* kfree(client);
* return error;
* }
* 总结:
* 1.为输入设备分配一个输入缓冲区evdev_client,用户存放input device层上报的数据
* 2.evdev_client记录到evdev中
* 3.evdev_client记录到file中,方便其他接口使用
* 一个设备节点对应一个cdev,一个cdev对应一个evdev,在evdev中记录了
* input_handler和input_dev的关系,并设置了一个缓冲队列,
* 一个input_dev对应一个input_handler,而一个input_handler可以对应多个input_handler
* *******************************************************************************
* 应用程序调用read函数时候实际调用的是evedv_read
*
* evdev_read函数分析:
* static ssize_t evdev_read(struct file *file, char __user *buffer,
* size_t count, loff_t *ppos)
* {
*
* struct evdev_client *client = file->private_data;
*
* struct evdev *evdev = client->evdev;
*
* struct input_event event;
*
* size_t read = 0;
* int error;
*
* if (count != 0 && count < input_event_size())
* return -EINVAL;
*
* for (;;) {
* if (!evdev->exist || client->revoked)
* return -ENODEV;
*
* if (client->packet_head == client->tail &&
* (file->f_flags & O_NONBLOCK))
* return -EAGAIN;
*
* if (count == 0)
* break;
*
* while (read + input_event_size() <= count &&
* evdev_fetch_next_event(client, &event)) {
*
* if (input_event_to_user(buffer + read, &event))
* return -EFAULT;
*
* read += input_event_size();
* }
*
* if (read)
* break;
*
* if (!(file->f_flags & O_NONBLOCK)) {
*
* error = wait_event_interruptible(evdev->wait,
* client->packet_head != client->tail ||
* !evdev->exist || client->revoked);
* if (error)
* return error;
* }
* }
*
* return read;
* }
* 总结:
* 1.如果没有数据,就会休眠等待
* 2.如果有数据,就从缓冲区client->bufsize[client->tail++]获取数据
* 通过input_event_to_user调用copy_to_user上报给用户
*
* 3.input_event函数将数据存放到缓冲区,且将队列唤醒
* 4.如果将数据上报最终将调用的是handler中的events或者event
* *************************************************************************************
* input_event函数分析:
* void input_event(struct input_dev *dev,
* unsigned int type, unsigned int code, int value)
* {
* unsigned long flags;
*
* if (is_event_supported(type, dev->evbit, EV_MAX)) {
*
* spin_lock_irqsave(&dev->event_lock, flags);
* input_handle_event(dev, type, code, value);
* spin_unlock_irqrestore(&dev->event_lock, flags);
* }
* }
* 总结:
* input_report_key(inputdev,pdesc->key_code,0);
*
*
* input_sync(inputdev);
*
*
* **********************************************************************************/
input子系统框图分析: