这一篇,我们来分析input_register_handler 这个非常重要的函数。就像之前说过的一样,这是注册一个驱动。
我们去input目录下看看那些文件调用的这个函数,分别有:evdev.c(evdev驱动)、joydev.c(joydev驱动)、keychord.c(按键驱动)、mousedev.c(鼠标驱动)。
也即是每个文件,对于一种驱动,并在里面进行注册驱动。
好的,那么我们以evdev.c为例子分析就好了。因为,触摸屏设备也是对应这个驱动。
1、看看入口函数
-
static const struct input_device_id evdev_ids[] = {
-
{ .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,
-
.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,够直接把。哈哈!
struct input_handler
evdev_handler 这几个机构体里面的几个元素都比较重要,后面都会用到,现在先来个大概的了解。
.event = evdev_event, : 当时间上报的时候,会调用到此函数。
.connect = evdev_connect, :当驱动和设备匹配的时候会调用到
.disconnect = evdev_disconnect, :这个还没研究
.fops = &evdev_fops, :这个handler的操作函数
.minor = EVDEV_MINOR_BASE, :EVDEV 此设备号的基值
.name = "evdev", : 名字啦
.id_table = evdev_ids, :驱动和设备是否匹配,需要通过id_table来验证。这里的evdev_ids 看到上面的注释没“match all devices ”,就是匹配所有设
备。
2、详细分析下input_register_handler 这个函数
-
/**
-
* input_register_handler - register a new input handler
-
* @handler: handler to be registered
-
*
-
* This function registers a new input handler (interface) for input
-
* devices in the system and attaches it to all input devices that
-
* are compatible with the 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); //初始化h_list头部
-
-
if (handler->fops != NULL) {
-
if (input_table[handler->minor >> 5]) {
-
retval = -EBUSY;
-
goto out;
-
}
-
input_table[handler->minor >> 5] = handler; //将handler插入数组,其位置是handler->minor >> 5,也就是除以32
-
}
-
-
list_add_tail(&handler->node, &input_handler_list); // 将handler->node插入到input_handler_list链表,深入代码分析可知,是插在input_handler_list头部的后面
-
-
list_for_each_entry(dev, &input_dev_list, node) //遍历input_dev_list链表,对每一个dev调用input_attach_handler函数,看是否匹配。
-
input_attach_handler(dev, handler);
-
-
input_wakeup_procfs_readers();
-
-
out:
-
mutex_unlock(&input_mutex);
-
return retval;
-
}
-
EXPORT_SYMBOL(input_register_handler);
上面的注释也说的很清楚,就是注册一个input_handler。函数的分析,代码旁边的注释也说了。
2.1 我们将重点集中下面这句代码。
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
先看看list_for_each_entry是怎么定义的
-
/**
-
* list_for_each_entry - iterate over list of given type
-
* @pos: the type * to use as a loop cursor.
-
* @head: the head for your list.
-
* @member: the name of the list_struct within the struct.
-
*/
-
#define list_for_each_entry(pos, head, member) \
-
for (pos = list_entry((head)->next, typeof(*pos), member); \
-
&pos->member != (head); \
-
pos = list_entry(pos->member.next, typeof(*pos), member))
注释说得很清楚,就是对于给定的某种类型的链表进行遍历,其实就是一个for 循环。我们带入就是下面这样
-
-
#define list_for_each_entry(dev, input_dev_list, node) \
-
for (dev= list_entry((input_dev_list)->next, typeof(*dev), node); \
-
&dev->node!= (input_dev_list); \
-
dev= list_entry(dev->node.next, typeof(*dev), node))
-
{
-
input_attach_handler(dev, handler);
-
}
-
再看看,list_entry的定义,就是我们熟悉的container_of,通过结构体里面某个元素的指针,找到结构体本身的指针,这里要找到的当然就dev结构体本身了,也就是input_device (关于这个我们留在下一篇分析)
-
/**
-
* list_entry - get the struct for this entry
-
* @ptr: the &struct list_head pointer.
-
* @type: the type of the struct this is embedded in.
-
* @member: the name of the list_struct within the struct.
-
*/
-
#define list_entry(ptr, type, member) \
-
container_of(ptr, type, member)
到了这里很明了,就是遍历input_dev_list链表,对每一个dev(input_device)调用input_attach_handler函数,看是否匹配。
2.2 input_attach_handler分析
先看看函数的定义
-
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
-
{
-
const struct input_device_id *id;
-
int error;
-
-
id = input_match_device(handler, dev);
-
if (!id)
-
return -ENODEV;
-
-
error = handler->connect(handler, dev, id);
-
if (error && error != -ENODEV)
-
pr_err("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和dev是否匹配,如果匹配成功,就会返回相应的ID,并调用handler里面的connect函数
2.2.1 input_match_device 函数分析
-
static const struct input_device_id *input_match_device(struct input_handler *handler,
-
struct input_dev *dev)
-
{
-
const struct input_device_id *id;
-
int i;
-
-
for (id = handler->id_table; id->flags || id->driver_info; 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);
-
-
if (!handler->match || handler->match(handler, dev))
-
return id;
-
}
-
-
return NULL;
-
}
因为evdev_handle->flag元素为空,并且
evdev_handle->match也为空,所以evdev_handle->id_table,所以匹配是成功的。
2.2.2 分析下handler->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;
-
//先在evdev_table[ ] 数组里面,找到一个还没有使用过的索引
-
for (minor = 0; minor < EVDEV_MINORS; minor++)
-
if (!evdev_table[minor])
-
break;
-
-
if (minor == EVDEV_MINORS) {
-
pr_err("no more free evdev devices\n");
-
return -ENFILE;
-
}
-
//申请一个evdev对象
-
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
-
if (!evdev)
-
return -ENOMEM;
-
//对evdev进行一些初始化
-
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->exist = true;
-
evdev->minor = minor;
-
//特别注意到evdev里面有一个handle的元素,以及对它的赋值,特别是handle.dev和handle.handler非常重要,这样才能把handle、dev、handler关联起来
-
evdev->handle.dev = input_get_device(dev); //指向我们的dev
-
evdev->handle.name = dev_name(&evdev->dev);
-
evdev->handle.handler = handler; //指向我们的handler
-
evdev->handle.private = evdev;
-
//也要特别注意到evdev里面有一个dev的元素,设备节点的生产就是靠它生成的
-
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); //得到设备号
-
evdev->dev.class = &input_class; //第二篇里面分析,有提到这个input_class哦!!
-
evdev->dev.parent = &dev->dev;
-
evdev->dev.release = evdev_free;
-
device_initialize(&evdev->dev);
-
//注册evdev里面的handle
-
error = input_register_handle(&evdev->handle);
-
if (error)
-
goto err_free_evdev;
-
//其实就是把evdev放入到evdev_table[]数组里面
-
error = evdev_install_chrdev(evdev);
-
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;
-
}
如上面的注释所述,先在evdev_talble[ ]数组里面找到一个没有使用过的索引,然后申请一个evdev,再就是初始化里面的元素,最后这个通过evdev_install_chrdev函数,将evdev放入到
evdev_talble[ ]数组里面。当然最后还要创建设备节点。
2.2.2.1 input_register_handle 分析
-
/**
-
* input_register_handle - register a new input handle
-
* @handle: handle to register
-
*
-
* This function puts a new input handle onto device's
-
* and handler's lists so that events can flow through
-
* it once it is opened using input_open_device().
-
*
-
* This function is supposed to be called from handler's
-
* connect() method.
-
*/
-
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);
-
-
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);
-
-
if (handler->start)
-
handler->start(handle);
-
-
return 0;
-
}
函数的头部说的很明白了,将handle放到device's list 和 handler list ,这样通过dev或者handler 就可以找到 handle ,结合之前的分析,通过handle 也可以找到dev和handler,这样他们就都关联起来了。
2.2.2.1 input_register_handle 分析
-
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;
-
}
很简单。
好了,evdev.c这个驱动就分析完了。下一篇我们来分析设备是如何注册的也就是input_regiter_device()。
阅读(2938) | 评论(0) | 转发(0) |