您的位置:首页 > 运维架构 > Linux

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

2012-05-27 18:39 405 查看




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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: