(本文所介绍内核基于linux-2.6.36内核)
了解完gpio设置之后,下面再对gpio的事件处理流程进行介绍。
Event事件处理定义在drivers/input/evdev.c
函数的注册与注销:drivers/input/evdev.c(line904-line925)
static struct input_handler evdev_handler = {
.event = evdev_event, // Pass incoming event to all connected clients.
.connect = evdev_connect, // Create new evdev device.
.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);
}
static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
module_init(evdev_init);
module_exit(evdev_exit);
在evdev中关键的处理功能从evdev_fops开始file operations定义了所有对event的打开关闭以及读写功能:
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
};
1.
static int evdev_open(struct inode *inode, struct file *file)
{
…
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table[i];
if (evdev)
get_device(&evdev->dev); // increment reference count for device.
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
bufsize = evdev_compute_buffer_size(evdev->handle.dev);
client = kzalloc(sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event),
GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
// 添加evdev_client结构到链表evdev->client_list中(好让输入事件到来的时候填写该结构并唤醒进程读取)
client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
evdev_attach_client(evdev, client);
error = evdev_open_device(evdev);
if (error)
goto err_free_client;
file->private_data = client;
nonseekable_open(inode, file);
…
}
2.
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval;
if (count < input_event_size()) //判断输入时间数据量是否正确
return -EINVAL;
//缓存中没有数据可读、设备是存在的,如果设置为NONBLOCK方式来读,立即返回.
if (client->head == client->tail && evdev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
// sleep until a condition gets true
retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);
if (retval)
return retval;
if (!evdev->exist)
return -ENODEV;
//从client-〉buffer中读取数据,并添加到链表中。
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
// copy_to_user
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
}
return retval;
}
到input_event_to_user为止一个键盘输入处理将数据传递给用户空间,处理结束。
与static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)功能相对应的,还有static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)功能,实现client-〉buffer的写操作。
总结一下,洋洋洒洒的把程序贴了这么多,无非是想把gpio的注册流程和event的处理流程一程序的形式梳理一遍,这两个工作流程其实都简单的体现了一个module的处理过程,本人水平有限,没能把更详尽的注释整理出来,也仅限于自己半懂得水平,刚开始接触这些东西,难免还有些错误,继续努力中。。。