现在的位置: 首页 > 综合 > 正文

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

2014年01月10日 ⁄ 综合 ⁄ 共 5026字 ⁄ 字号 评论关闭


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(&evdev_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 evdev
if (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对应的handle
retval = 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_data
return 0;

 err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
 err_put_evdev:
put_device(&evdev->dev);
return error;
}

抱歉!评论已关闭.