linux input子系统(二)- input event drivers evdev 驱动分析

input子系统分为了input device drivers和input event drivers,看图
                                               linux input子系统(二)- input event drivers evdev 驱动分析_第1张图片
        可以看到,在kernel space中,input -core 管理着 input device drivers 以及input event drivers,其中在 input device drivers中,当遇到有按键或者是TP触摸时甚至我们假定的sensor的中断时,调用一个函数即在input-core中的input_event的函数(input.c中定义,但是一般不直接调用,还有一层函数的封装),在input-core中input_event函数中,假如是正确的 事件的话,会通过input-core层之前注册的input event drivers 定义的event函数,将键值或者是坐标值写到已经定义的buffer中,当底层的input device drivers 进行input_sync时,作为一组数据保存,上层函数通过read 函数 ,函数中input_event_to_user将数据拷贝到用户空间。接下来我会一一分析。
最典型的input event drivers 是evdev的事件驱动 的drivers,基本管理着大部分的input device drivers。
static const struct input_device_id evdev_ids[] = {
	{ .driver_info = 1 },	/* Matches all devices */       //能够匹配到所有的已经注册在input子系统上dev  
	{ },			/* Terminating zero entry */
};


MODULE_DEVICE_TABLE(input, evdev_ids);


static struct input_handler evdev_handler = {
	.event		= evdev_event,                     //dev 进行input_event 时实际上调用的函数。
	.connect	= evdev_connect,                   //注册匹配成功后,调用connect函数
	.disconnect	= evdev_disconnect,                //注册不成功时,调用disconnect函数
	.fops		= &evdev_fops,                     //进行读写等操作
	.minor		= EVDEV_MINOR_BASE,                //次版本号是从64开始 
	.name		= "evdev",
	.id_table	= evdev_ids,                      //和dev匹配时用到了id_table
};


static int __init evdev_init(void)
{
	return input_register_handler(&evdev_handler);
}


static void __exit evdev_exit(void)
{
	input_unregister_handler(&evdev_handler);
}


module_init(evdev_init);
module_exit(evdev_exit);
接下来讲一下evdev.c中定义的几个比较重要的函数。
static int evdev_connect (struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
        这个函数在input_attach_handler(input.c中定义的),当match函数成功时,即进行connect函数,就是调用的这个connect函数(evdev为例,当然joydev,moucedev也有自己的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++)                  //一个handler只能支持32个设备
		if (!evdev_table[minor])                                    //直到检查到evdev_table是否有空闲的,空闲时此时获得了minor
			break;

	if (minor == EVDEV_MINORS) {                                  //检查是否已经等于了最大的32,等于32就没有空间了
		pr_err("no more free evdev devices\n");
		return -ENFILE;
	}

	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);          //申请evdev空间
	if (!evdev)
		return -ENOMEM;

	INIT_LIST_HEAD(&evdev->client_list);                      //初始化client_list链表
	spin_lock_init(&evdev->client_lock);                      
	mutex_init(&evdev->mutex);
	init_waitqueue_head(&evdev->wait);                       //初始化等待队列

	dev_set_name(&evdev->dev, "event%d", minor);             //在/dev/input/生成event0,event1...的文件,当然这个是设置name
	evdev->exist = true;
	evdev->minor = minor;

	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;

	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);   //此版本是evdev的起始次版本64+minor,所以就是64,65..95
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);

	error = input_register_handle(&evdev->handle);                  //注册handle,这个将handler以及dev产生更亲密的关系。
	if (error)
		goto err_free_evdev;

	error = evdev_install_chrdev(evdev);                         //vdev_table[evdev->minor] = evdev; vdev_table赋值
	if (error)
		goto err_unregister_handle;

	error = device_add(&evdev->dev);                           //在/dev/input/生成event0,event1等
	if (error)
		goto err_cleanup_evdev;

	return 0;

 err_cleanup_evdev:
	evdev_cleanup(evdev);
 err_unregister_handle:
	input_unregister_handle(&evdev->handle);
 err_free_evdev:
	put_device(&evdev->dev);
	return error;
}
这里面还有一个函数需要来看一下
int input_register_handle(struct input_handle *handle)
handle是存放一对匹配好的handler以及dev的。这个函数的作用是利于handler访问dev,也有利于dev访问handler的
int input_register_handle(struct input_handle *handle)
{
	struct input_handler *handler = handle->handler;
	struct input_dev *dev = handle->dev;
	int error;

	/*
	 * We take dev->mutex here to prevent race with
	 * input_release_device().
	 */
	error = mutex_lock_interruptible(&dev->mutex);
	if (error)
		return error;

	/*
	 * Filters go to the head of the list, normal handlers
	 * to the tail.
	 */
	if (handler->filter)
		list_add_rcu(&handle->d_node, &dev->h_list);
	else
		list_add_tail_rcu(&handle->d_node, &dev->h_list);               //将handle->d_node添加到dev->h_list中

	mutex_unlock(&dev->mutex);

	/*
	 * Since we are supposed to be called from ->connect()
	 * which is mutually exclusive with ->disconnect()
	 * we can't be racing with input_unregister_handle()
	 * and so separate lock is not needed here.
	 */
	list_add_tail_rcu(&handle->h_node, &handler->h_list);             //将handle->d_node添加到handler->h_list中

	if (handler->start)
		handler->start(handle);

	return 0;
}
用一个图很直观的体现一下(注:摘抄的)
linux input子系统(二)- input event drivers evdev 驱动分析_第2张图片

linux input子系统(二)- input event drivers evdev 驱动分析_第3张图片

还有一个函数是
static void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value)
当底层传入event事件时,都会进入这个函数(异常除外,以evdev为例)
static void evdev_event(struct input_handle *handle,
			unsigned int type, unsigned int code, int value)
{
	struct evdev *evdev = handle->private;
	struct evdev_client *client;
	struct input_event event;
	ktime_t time_mono, time_real;

	time_mono = ktime_get();
	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());

	event.type = type;                         //将传入的type等赋值给event
	event.code = code;
	event.value = value; 

	rcu_read_lock();

	client = rcu_dereference(evdev->grab);         //前面的evdev->grab并没有动,所以没有

	if (client)
		evdev_pass_event(client, &event, time_mono, time_real);
	else
		list_for_each_entry_rcu(client, &evdev->client_list, node)   //evdev->client_list 是在用户空间打开input系统时
			evdev_pass_event(client, &event, time_mono, time_real);  //将evdev与evdev->client_list发生关系的

	rcu_read_unlock();

	if (type == EV_SYN && code == SYN_REPORT)                      //在设备进行input_sync时就会调用这个
		wake_up_interruptible(&evdev->wait);                       //唤醒等待队列
}

看一下
static void evdev_pass_event(struct evdev_client *client,
    struct input_event *event,
    ktime_t mono, ktime_t real)


static void evdev_pass_event(struct evdev_client *client,
			     struct input_event *event,
			     ktime_t mono, ktime_t real)
{
	event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
					mono : real);

	/* Interrupts are disabled, just acquire the lock. */
	spin_lock(&client->buffer_lock);

	client->buffer[client->head++] = *event;                 //将event赋值给buffer,这个buffer是给用户来读的
	client->head &= client->bufsize - 1;          

	if (unlikely(client->head == client->tail)) {           //不太可能发生的,就是head == tail的时候
		/*
		 * This effectively "drops" all unconsumed events, leaving
		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
		 */
		client->tail = (client->head - 2) & (client->bufsize - 1);

		client->buffer[client->tail].time = event->time;
		client->buffer[client->tail].type = EV_SYN;
		client->buffer[client->tail].code = SYN_DROPPED;
		client->buffer[client->tail].value = 0;

		client->packet_head = client->tail;
		if (client->use_wake_lock)
			wake_unlock(&client->wake_lock);
	}

	if (event->type == EV_SYN && event->code == SYN_REPORT) {        //检测是否是input_sync同步事件
		client->packet_head = client->head;                      //重新认为是新的一组数据
		if (client->use_wake_lock)  
			wake_lock(&client->wake_lock);
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}

	spin_unlock(&client->buffer_lock);
}
将数据存储到所谓的buffer中后,上层通过read函数读取走已存的数据,具体函数名是
static ssize_t evdev_read(struct file *file, char __user *buffer,
 size_t count, loff_t *ppos)

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;
	int retval = 0;

	if (count < input_event_size())
		return -EINVAL;

	if (!(file->f_flags & O_NONBLOCK)) {
		retval = wait_event_interruptible(evdev->wait,
				client->packet_head != client->tail ||
				!evdev->exist);
		if (retval)
			return retval;
	}

	if (!evdev->exist)
		return -ENODEV;

	while (retval + input_event_size() <= count &&
	       evdev_fetch_next_event(client, &event)) {

		if (input_event_to_user(buffer + retval, &event))
			return -EFAULT;

		retval += input_event_size();
	}

	if (retval == 0 && (file->f_flags & O_NONBLOCK))
		return -EAGAIN;

	return retval;
}







你可能感兴趣的:(linux驱动,linux,linux驱动之子系统)