linux驱动——input输入子系统(3)——evdev

linux驱动——input输入子系统(1)—输入子系统核心层(Input Core)的地址链接linux驱动——input输入子系统(2)——handler的地址链接

evdev输入事件驱动,为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。

1、evdev有关的代码都在Evdev.c (linux2.6.28\drivers\input)文件中,作为模块存在。

module_init(evdev_init);module_exit(evdev_exit);

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

static int __init evdev_init(void){return input_register_handler

其中有:

static struct input_handler evdev_handler = {.event= evdev_event,.connect= evdev_connect,.disconnect= evdev_disconnect,.fops= &evdev_fops,.minor= EVDEV_MINOR_BASE,

其中有:#define EVDEV_MINOR_BASE64

因为一个handler可以处理32个设备,所以evdev_handler所能处理的设备文件范围为(13,64)~(13,64+32),其中13是所有输入设备的主设备号。.name= "evdev",.id_table= evdev_ids,

其中:static const struct input_device_id evdev_ids[] = {{ .driver_info = 1 },/* Matches all devices */{ },/* Terminating zero entry */};

evdev_ids没有定义flags,也没有定义匹配属性值。这个evdev_ids的意思就是:evdev_handler可以匹配所有 input_dev设备,也就是所有的input_dev发出的事件,都可以由evdev_handler来处理。

};}

2、如果input_dev和handler匹配成功后,会调用handler->connect()函数,现在就来分析evdev_connect函数,源码如下所示:

/** Create new evdev device. Note that input core serializes calls* to connect and disconnect so we don’t need to lock evdev_table here.*/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++)if (!evdev_table[minor])break;其中有定义:#define EVDEV_MINORS32

static struct evdev *evdev_table[EVDEV_MINORS];

struct evdev {int exist;int open;int minor;char name[16];struct input_handle handle;wait_queue_head_t wait;struct evdev_client *grab;struct list_head client_list;spinlock_t client_lock; /* protects client_list */struct mutex mutex;struct device dev;};

表示evdev_handler所表示的32个设备,这个循环为了找到空的一项if (minor == EVDEV_MINORS) { 没找到,则退出printk(KERN_ERR "evdev: no more free evdev devices\n");return -ENFILE;}evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);if (!evdev)return -ENOMEM;INIT_LIST_HEAD(&evdev->client_list); 初始化spin_lock_init(&evdev->client_lock);mutex_init(&evdev->mutex);init_waitqueue_head(&evdev->wait);snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);evdev->exist = 1;evdev->minor = minor;evdev->handle.dev = input_get_device(dev); 对evdev中handle的初始化,这些初始化的目的是使input_dev和input_handler联系起来。evdev->handle.name = evdev->name;evdev->handle.handler = handler;evdev->handle.private = evdev;strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); 初始化一个evdev->dev的设备evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);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); 注册一个input_handle结构体if (error)goto err_free_evdev;error = evdev_install_chrdev(evdev);源码如下:

static int evdev_install_chrdev(struct evdev *evdev){/** No need to do any locking here as calls to connect and* disconnect are serialized by the input core*/evdev_table[evdev->minor] = evdev;return 0;}if (error)goto err_unregister_handle;error = device_add(&evdev->dev); 和设备模型有关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;}

3、evdev设备的打开

对主设备号为INPUT_MAJOR的设备结点进行操作,会将操作集转换成handler的操作集。在evdev_handler中定义了一个fops集合,被赋值为evdev_fops的指针,evdev_fops结构的定义如下所示:

static const struct file_operations evdev_fops = {.owner= THIS_MODULE,.read= evdev_read,.write= evdev_write,.poll= evdev_poll,.open= evdev_open,.release= evdev_release,.unlocked_ioctl= evdev_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl= evdev_ioctl_compat,#endif.fasync= evdev_fasync,.flush= evdev_flush};

当用户程序调用open时,会调用evdev_open函数,源码如下:

static int evdev_open(struct inode *inode, struct file *file){struct evdev *evdev;struct evdev_client *client;int i = iminor(inode) – EVDEV_MINOR_BASE; 得到了在evdev_table[]中的序号int error;if (i >= EVDEV_MINORS)return -ENODEV;error = mutex_lock_interruptible(&evdev_table_mutex);if (error)return error;evdev = evdev_table[i]; 得到struct evdevif (evdev)get_device(&evdev->dev); 增加引用计数mutex_unlock(&evdev_table_mutex);if (!evdev)return -ENODEV;client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); 分配一个struct evdev_client结构体的空间

其中:struct evdev_client {struct input_event buffer[EVDEV_BUFFER_SIZE];int head;int tail;spinlock_t buffer_lock; /* protects access to buffer, head and tail */struct fasync_struct *fasync;struct evdev *evdev;struct list_head node;};if (!client) {error = -ENOMEM;goto err_put_evdev;}spin_lock_init(&client->buffer_lock);client->evdev = evdev;evdev_attach_client(evdev, client); 将client挂到evdev->client_list上。error =evdev_open_device(evdev); 打开输入设备

static int evdev_open_device(struct evdev *evdev){int retval;retval = mutex_lock_interruptible(&evdev->mutex);if (retval)return retval;if (!evdev->exist) 判断设备的存在retval = -ENODEV;else if (!evdev->open++) { 如果是第一次打开,调用input_open_device打开evdev对应的handleretval = input_open_device(&evdev->handle);if (retval)evdev->open–;}mutex_unlock(&evdev->mutex);return retval;}if (error)goto err_free_client;file->private_data = client; 将 client赋给file的private_datareturn 0;err_free_client:evdev_detach_client(evdev, client);kfree(client);err_put_evdev:put_device(&evdev->dev);return error;}

没有伞的孩子必须努力奔跑!

linux驱动——input输入子系统(3)——evdev

相关文章:

你感兴趣的文章:

标签云: