输入子系统4

应用程序中调用了输入子系统的代码,数据是如何传递给用户层的?

 open("/dev/event1", O_RDWR);
---------------------------------------------
vfs
	sys_open();
		struct file  file->f_ops = cdev->ops;
		file->f_ops->open();
-------------------------------------------
设备驱动层:输入子系统
 input handler 层:evdev.c
		cdev;
	   xxx_ops = {
			.open = xxx_open,
			.write = xxx_write,
	   }


	 static const struct file_operations evdev_fops = {
					.owner		= THIS_MODULE,
					.read		= evdev_read,
					.write		= evdev_write,
					.poll		= evdev_poll,
					.open		= evdev_open,
	 }
	
	实际最终调用了evdev_open();
		|
		// 实际cdev是谁,就是evdev_connect注册的那个
		struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);

		// 通过儿子,找到老母input device
		unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);

		// size就包含了很多input_event
		unsigned int size = sizeof(struct evdev_client) +
						bufsize * sizeof(struct input_event);

		struct evdev_client *client;

		// 分配一个client对像,描述一个缓冲队列,存放的就是input_event
		client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);

		// client中有一个缓冲区
		client->bufsize = bufsize;
		spin_lock_init(&client->buffer_lock);
		//在client中记录evdev
		client->evdev = evdev;
		// 将client加入到evdev中一个小链表
		evdev_attach_client(evdev, client);
				|
				list_add_tail_rcu(&client->node, &evdev->client_list);

		// 将client记录到file,方便其他的接口使用
		file->private_data = client;

		总结:
			1,为输入设备分配一个缓冲区evdev_client,用户存放input device层上报的数据
			2,evdev_client记录到evdev中
			3,evdev_client记录到file中,方面其他的接口使用

应用程序中read,是如何获取到数据的

	APP应用调用read函数
	ssize_t read(int fd, void *buf, size_t count)

-----------------------------------------------------------------------
	vfs
		sys_read();
			file->f_ops->read();

-------------------------------------------------------------------
	evdev.c
	static const struct file_operations evdev_fops = {
		.read		= evdev_read,
	}

	evdev_read(struct file *file, char __user *buffer,
			  size_t count, loff_t *ppos)
			|
		// 获取到open中分配的缓冲区对象
		struct evdev_client *client = file->private_data;
		//获取到evdev
		struct evdev *evdev = client->evdev;
		//表示一个数据包,要给用户
		struct input_event event;

		for (;;) {
			// 实现非阻塞
			if (client->packet_head == client->tail &&
				(file->f_flags & O_NONBLOCK))
				return -EAGAIN;

				while (read + input_event_size() <= count &&
				// 1从缓冲区获取数据,存放在 input_event数据包
				   evdev_fetch_next_event(client, &event)) {
							|
							*event = client->buffer[client->tail++];
				// 2, 将数据上报给用户
				if (input_event_to_user(buffer + read, &event))
							|
							copy_to_user(buffer, event, sizeof(struct input_event)

				// 3,统计上报多少数据
				read += input_event_size();
			}

			// 如果当前是阻塞模式
			if (!(file->f_flags & O_NONBLOCK)) {
				//等待---休眠,需要被唤醒,有数据时候唤醒
				error = wait_event_interruptible(evdev->wait,
						client->packet_head != client->tail ||
						!evdev->exist || client->revoked);
		}

		总结:
			1,如果没有数据,就会休眠等待
			2,如果有数据,就从缓冲区client->buffer[client->tail++]拿数据
				通过copy_to_user上报给用户
		
			疑问:
				数据到底是如何存放在缓冲区的
				等待队列是谁唤醒的
				input_report_key(inputdev, pdesc->key_code, 0);
				input_sync(inputdev);//上报数据结束

input_event()上报数据实现过程

input_report_key(inputdev, pdesc->key_code, 0);
	input_sync(inputdev);//上报数据结束
		|//input_event(dev, EV_KEY, code, !!value);
		input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value);// 上报数据
				|
				input_handle_event(dev, type, code, value);
						|
						// 如果将数据交给input handler去处理
						if (disposition & INPUT_PASS_TO_HANDLERS) {
							struct input_value *v;
							//将input device获取到数据暂存一下input value
							v = &dev->vals[dev->num_vals++];
							v->type = type;
							v->code = code;
							v->value = value;


							input_pass_values(dev, dev->vals, dev->num_vals)
								|
								// 从input device中获取到input handle
							else {
	
							list_for_each_entry_rcu(handle, &dev->h_list, d_node)
								if (handle->open)
									count = input_to_handler(handle, vals, count);
											|
										// 通过handle儿子找到handler父亲
										struct input_handler *handler = handle->handler;
										// 如果有events函数指针,那就调用
										if (handler->events)
											handler->events(handle, vals, count);
										else if (handler->event)//否则就调用event();
											for (v = vals; v != end; v++)
												handler->event(handle, v->type, v->code, v->value);							
										
						}

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,
};
			总结: 如果将数据上报,最终是调用handler中events()或者event()
				实际是evdev.c
				.event		= evdev_event,
				.events		= evdev_events,