/**
入口函数。
这是:事件处理层向核心层注册input_handler
input_register_handler()函数的实现在以前博文中浅析过了。
*/
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
/**
事件处理器,对输入事件的具体处理
*/
static struct input_handler evdev_handler = {
/**
设备驱动层调用input_event()向核心层上报的事件,最终会到达事件处理层 ,事件处理层的这个函数会被调用。事件流程以前的博文已浅析。
*/
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
.....
error = handler->connect(handler, dev, id);
if(error)
{
....
}
return error;
}
下面看event_connect函数的实现
static int event_connect(struct input_handler * handler,struct input_dev * dev,const struct input_device_id * id)
{
struct evdev * evdev;
int minor;
int error;
/**
#define EVDEV_MINORS 32
对evdev_table[32]数组遍历,目的是在数组中找出一个空缺项
下边的代码会生成一个evdev,为evdev放入这个数组中做准备,
下面讨论一下evdev_table[]这个数组
它是再什么时候被构造的,什么时候被填充的,又是什么时候从里面取出元素的
一指针数组 长度32 里面存放的元素都是 struct evdev *
static struct evdev *evdev_table[EVDEV_MINORS];
填充:
evdev_connect(...)
{
evdev_install_chrdev(evdev)
{
* No need to do any locking here as calls to connect and
* disconnect are serialized by the input core
//官方这里说:这里不需要使用互斥机制来保护临界区
//在evdev_remove_chrdev()函数中是需要避免竞态发生的。难道一下子不会匹配成功好几个?,
//为什么删除的时候却可能引起并发从而要防止竞太的发生呢?
//在调用event_connect的前面几个函数input_register_device、input_register_hander函数中操作链表也没有使用互斥保护机制的,
//请教:为什么?
evdev_table[evdev->minor] = evdev;
return 0;
}
}
从evdev_table[]数组中删除evdev
evdev_disconnect(struct input_handle *handle)
{
evdev_cleanup(evdev)
{
evdev_remove_chrdev(evdev)
{
//获取互斥锁 --- 访问临界区 ----释放互斥锁
mutex_lock(&evdev_table_mutex);
evdev_table[evdev->minor] = NULL;
mutex_unlock(&evdev_table_mutex);
}
}
}
*/
for (int minor = 0; minor < EVDEV_MINORS; ++minor)
{
/**
如果evdev_table[]有空缺项,就跳出循环
那么minor就记录了这个空缺项在evdev_table[]中的索引值
*/
if (!evdev_table[minor])
{
break;
}
}
/**
对evdev_table[]是否满了的判断
*/
if (minor == EVDEV_MINORS)
{
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
}
/**
为evdev分配内存空间
*/
evdev = kzalloc(sizeof(struct devdev),GFP_KERNEL);
if (!evdev)
{
return -ENOMEM;
}
/**
初始化 链表、自旋锁、互斥锁、等待队列
client_list : 所有的evdev都会放到这个连表上
*/
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
/**
设置evdev的名字。evevt0、event1...event31。递增的形式
在/dev/input/中出现
看,minor在这里发挥作用了,
*/
dev_set_name(&evdev->dev,"event%d",minor);
evdev->exist = 1;
evdev->minor = minor;
/**
下面的代码是对input_handle进行初始化。
input_handle:
用来连接input_dev和input_handler
*/
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
/**
下面的代码对evdev->dev进行初始化
会把它放入到linux设备驱动模型中,在放入之前先初始化一下。
*/
evdev->dev.devt = MKDEV(INPUT_MAJOR,EVDEV_MINOR_BASE + minor);
/**
设置设备所属的类。这样会在/sys/class/input/下面显示设备的目录
*/
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
/**
设置释放函数,
当evdev设备的引用计数为0的时候,这个函数会自动被调用。
*/
evdev->dev.release = evdev_free;
/**
初始化了evdev->dev中的一些成员
看看它的源码:
device_initialize()
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
device_pm_init(dev);
set_dev_node(dev, -1);
}
*/
device_initialize(&evdev->dev);
/**
注册一个新的input_handle
就是把input_handle挂到input_dev维护的dev->h_list链表中、
input_handler维护的handler->h_list链表中
看源码:
int input_register_handle(struct input_handle *handle)
{
//从input_handle中取出它所指向的input_handler
struct input_handler *handler = handle->handler;
//从input_handle中取出它所指向的input_dev
struct input_dev *dev = handle->dev;
int error;
error = mutex_lock_interruptible(&dev->mutex);
if (error){
return error;
}
if (handler->filter)
list_add_rcu(&handle->d_node, &dev->h_list);
else
//将input_handle挂接到input_dev维护的dev->h_list链表中
list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex);
//将input_handle挂接到input_handler维护的handler->h_list链表中
list_add_tail_rcu(&handle->h_node, &handler->h_list);
}
//如果input_handler提供了start函数,就调用它
if (handler->start){
handler->start(handle);
}
*/
error = input_register_handle(&evdev->handle);
if (error){
goto err_free_evdev;
}
/**
将设置好的evdev放入到evdev_table[]中
源码:
static int evdev_install_chrdev(struct evdev *evdev)
{
//依据次设备号为索引值将设置好的evdev放入到evdev_table[]中。还是那个问题 不明白为什么不保护起来.如果能并发就可能会引起竞态,既然有竞态可能发生,为什么临界区不用互斥机制保护起来呢?
evdev_table[evdev->minor] = evdev;
return 0;
}
*/
error = evdev_install_chrdev(evdev);
if (error)
{
goto err_unregister_handle;
}
/**
任何设备的添加都会经过这个函数。
*/
error = device_add(&evdev->dev);
if (error)
{
goto err_cleanup_evdev;
}
return 0;
}