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

我对linux理解之input一

2012-08-16 10:20 260 查看
我们先看下input的注册过程:

input_register_device(input_dev):

int input_register_device(struct input_dev *dev)

{

static atomic_t input_no = ATOMIC_INIT(0);

struct input_handler *handler;

const char *path;

int error;

__set_bit(EV_SYN, dev->evbit);//支持同步事件

/*

* If delay and period are pre-set by the driver, then autorepeating

* is handled by the driver itself and we don't do it in input.c.

*/

init_timer(&dev->timer);//为重复按键做准备

if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

dev->timer.data = (long) dev;

dev->timer.function = input_repeat_key;

dev->rep[REP_DELAY] = 250;

dev->rep[REP_PERIOD] = 33;

}

if (!dev->getkeycode)//如果没设置,则设置成默认的

dev->getkeycode = input_default_getkeycode;

if (!dev->setkeycode)

dev->setkeycode = input_default_setkeycode;

dev_set_name(&dev->dev, "input%ld",

(unsigned long) atomic_inc_return(&input_no) - 1);//按顺序地去定义input序号

error = device_add(&dev->dev);//将input dev添加到sys系统中,包括创建一些input的属性文件

if (error)

return error;

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);//这里路径是上面device_add产生的

printk(KERN_INFO "input: %s as %s\n",

dev->name ? dev->name : "Unspecified device", path ? path : "N/A");

kfree(path);

error = mutex_lock_interruptible(&input_mutex);

if (error) {

device_del(&dev->dev);

return error;

}

list_add_tail(&dev->node, &input_dev_list);//添加到input设备列表里面

list_for_each_entry(handler, &input_handler_list, node)//对input handler列表中的每个handler都进行匹配,这里input_handler_list怎么来的呢?我们在 input_register_handler找到它的形成过程

input_attach_handler(dev, handler);//匹配dev和handler

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

return 0;

}

我们看下input_attach_handler(dev, handler):

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

{

const struct input_device_id *id;

int error;

if (handler->blacklist && input_match_device(handler->blacklist, dev))//如果在黑名单里面就返回

return -ENODEV;

id = input_match_device(handler->id_table, dev);//匹配handler->id_table和dev

if (!id)

return -ENODEV;

error = handler->connect(handler, dev, id);//调用handler的connect连接handler、 dev,这个函数很重要,起到了承上启下的作用。

if (error && error != -ENODEV)

printk(KERN_ERR

"input: failed to attach handler %s to device %s, "

"error: %d\n",

handler->name, kobject_name(&dev->dev.kobj), error);

return error;

}

input_match_device(handler->id_table, dev):

static const struct input_device_id *input_match_device(const struct input_device_id *id,

struct input_dev *dev)

{

int i;

for (; id->flags || id->driver_info; id++) {//对handler中的每个id都进行查询

if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)

if (id->bustype != dev->id.bustype)

continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)

if (id->vendor != dev->id.vendor)

continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

if (id->product != dev->id.product)

continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

if (id->version != dev->id.version)

continue;

MATCH_BIT(evbit, EV_MAX);

MATCH_BIT(keybit, KEY_MAX);

MATCH_BIT(relbit, REL_MAX);

MATCH_BIT(absbit, ABS_MAX);

MATCH_BIT(mscbit, MSC_MAX);

MATCH_BIT(ledbit, LED_MAX);

MATCH_BIT(sndbit, SND_MAX);

MATCH_BIT(ffbit, FF_MAX);

MATCH_BIT(swbit, SW_MAX);

return id;

}

return NULL;

}

该函数会对handler中的每个id都进行查询,先根据id->flags设置去比较,然后比较具体的位,MATCH_BIT定义如下:

#define MATCH_BIT(bit, max) \

for (i = 0; i < BITS_TO_LONGS(max); i++) \

if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \

break; \

if (i != BITS_TO_LONGS(max)) \

continue;

可以看出来是id->bit[i]与dev->bit[i]比较。

从整体上看,匹配的过程还算比较简单。分析中有几个新的地方input_handler_list和handler->connect。

其实这些都是input子系统最顶层做的工作,最顶层可以有evdev,joydev,mousedev等,当然用户完全可以构建一个自己的dev。我们就挑选evdev做分析吧,也是最常用的一种。

static const struct input_device_id evdev_ids[] = {//还记得上面匹配函数里面用到的id吗?就是它哦

{ .driver_info = 1 }, /* Matches all devices */

{ }, /* Terminating zero entry */

};

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {

.event = evdev_event,

.connect = evdev_connect,//看到了吧,匹配函数中的handler->connect

.disconnect = evdev_disconnect,

.fops = &evdev_fops,

.minor = EVDEV_MINOR_BASE,

.name = "evdev",

.id_table = evdev_ids,

};

static int __init evdev_init(void)

{

return input_register_handler(&evdev_handler);

}

evdev初始化是注册了handler:

int input_register_handler(struct input_handler *handler)

{

struct input_dev *dev;

int retval;

retval = mutex_lock_interruptible(&input_mutex);

if (retval)

return retval;

INIT_LIST_HEAD(&handler->h_list);

if (handler->fops != NULL) {

if (input_table[handler->minor >> 5]) {

retval = -EBUSY;

goto out;

}

input_table[handler->minor >> 5] = handler;//放到input_table

}

list_add_tail(&handler->node, &input_handler_list);//添加到handler列表中,这样就形成了input_handler_list

list_for_each_entry(dev, &input_dev_list, node)

input_attach_handler(dev, handler);//这边也进行匹配了,所以无论是handler还是dev注册都会调用匹配函数

input_wakeup_procfs_readers();

out:

mutex_unlock(&input_mutex);

return retval;

}

我们下面分析一下evdev_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++)//找到一个空的minor

if (!evdev_table[minor])

break;

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);

dev_set_name(&evdev->dev, "event%d", minor);//evdev的名字,即event*

evdev->exist = 1;

evdev->minor = minor;

evdev->handle.dev = input_get_device(dev);//将dev赋值给handle

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

evdev->handle.handler = handler;//将handler赋值给handle

evdev->handle.private = evdev;

//可以看出handle将dev和handler联系到一块了

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);//注册handle,其实就是将handle再跟dev和handler分别联系起来,这样三者就真正地互相联系到一块了

if (error)

goto err_free_evdev;

error = evdev_install_chrdev(evdev);//把evdev添加到evdev_table中

if (error)

goto err_unregister_handle;

error = device_add(&evdev->dev);//将evdev添加到/sys/中

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;

}

我们先解释input_register_handle(&evdev->handle):

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;

list_add_tail_rcu(&handle->d_node, &dev->h_list);//将handle添加到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(&handle->h_node, &handler->h_list);//将handle添加到handler的h_list

if (handler->start)

handler->start(handle);

return 0;

}

将handle分别添加到dev和handler的h_list中,这样三者真正地联系起来了,可以互相访问。

我们可以看到evdev才是真正用户可以操作的设备,evdev中的handle把handler和dev联系到了一块,同时将evdev添加到了sys中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: