输入子系统
2016-05-21 15:25
211 查看
1、核心层:
linux-2.6.22.6\drivers\input\input.c:
①、注册input_handler:
②、注册输入设备:
③、如何建立连接:
①②中都要建立连接,用evdev.c来示例如何建立连接:
这样input_dev和input_handler之间就通过handle建立了连接。
2、稳定程序层:
问:input_table数组由谁赋值?
3、设备层:
以示例程序gpio_keys.c为例:
执行input_register_device函数以开始进行输入设备注册并建立连接。
4、probe是如何被调用的?
安装模块时,①、在xxx_drv.c中xxx_init被执行,进而执行platform_driver_register>>driver_register>>bus_add_driver,把driver放入bus的drv链表,从bus的dev链表中取出每一个dev,用bus的match函数判断dev能否支持drv(通常通过结构体中的名称比较,但也有例外),若可以支持,调用drv的probe函数。②、在xxx_dev.c中xxx_init被执行,进而执行platform_device_register>>platform_device_add>>device_add,把device放入bus的dev链表,从bus的drv链表中取出每一个drv,用bus的match函数判断drv能否支持dev(通常通过结构体中的名称比较,但也有例外),若可以支持,调用dev的probe函数。
5、如何读?
app : read
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
……………
应用程序运行时无数据并且是非阻塞方式打开,线程就会进入休眠,谁来唤醒?由事件来唤醒:
那么evdev_event又被谁调用?
以GPIO按键驱动程序为例说明:在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数
linux-2.6.22.6\drivers\input\keyboard\gpio_keys.c:
linux-2.6.22.6\drivers\input\input.c:
static int __init input_init(void)
register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops=
{ .owner = THIS_MODULE, .open = input_open_file, };
static int input_open_file(struct inode *inode, struct file *file)
struct input_handler *handler = input_table[iminor(inode) >> 5]; const struct file_operations *old_fops, *new_fops = NULL; ... new_fops = fops_get(handler->fops) ... file->f_op = new_fops; new_fops->open(inode, file);
①、注册input_handler:
int input_register_handler(struct input_handler *handler)
list_add_tail(&handler->node, &input_handler_list);//放入链表尾部
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); //对于每个条目,调用input_attach_handler函数,根据dev的id_table判断能否支持这个input_handler
id = input_match_device(handler->id_table, dev); if (!id) return -ENODEV; handler->connect(handler, dev, id); //如果支持,则建立连接[/code]
②、注册输入设备:
int input_register_device(struct input_dev *dev)
list_add_tail(&dev->node, &input_dev_list);//放入链表尾部
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); //对于每个条目,调用input_attach_handler函数,根据input_handler的id_table判断能否支持这个dev
id = input_match_device(handler->id_table, dev); if (!id) return -ENODEV; handler->connect(handler, dev, id); //如果支持,则建立连接[/code]
③、如何建立连接:
①②中都要建立连接,用evdev.c来示例如何建立连接:
static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id)
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
evdev->handle.dev = dev;//指向input_dev
evdev->handle.handler = handler;//指向input_handler
input_register_handle(&evdev->handle);
struct input_handler *handler = handle->handler;
list_add_tail(&handle->d_node, &handle->dev->h_list);//将handle结构体的d_node放入input_dev结构体的h_list
list_add_tail(&handle->h_node, &handler->h_list);//将handle结构体的h_node放入input_handler结构体的h_list
这样input_dev和input_handler之间就通过handle建立了连接。
2、稳定程序层:
问:input_table数组由谁赋值?
static int __init evdev_init(void)//evdev.c、keyboard.c、mouse.c 等的初始化函数,这里以evdev.c的初始化函数为示例
int input_register_handler(struct input_handler *handler)
input_table[handler->minor >> 5] = handler;
3、设备层:
以示例程序gpio_keys.c为例:
struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, .remove = __devexit_p(gpio_keys_remove), .driver = { .name = "gpio-keys", } };
static int __init gpio_keys_init(void) { return platform_driver_register(&gpio_keys_device_driver); }
static int __devinit gpio_keys_probe(struct platform_device *pdev) { ... struct input_dev *input; ... input = input_allocate_device(); ... set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, button->desc ? button->desc : "gpio_keys", pdev); ... error = input_register_device(input); //************************************************* ****** 其他硬件相关设置 ******* *************************************************// }
执行input_register_device函数以开始进行输入设备注册并建立连接。
4、probe是如何被调用的?
安装模块时,①、在xxx_drv.c中xxx_init被执行,进而执行platform_driver_register>>driver_register>>bus_add_driver,把driver放入bus的drv链表,从bus的dev链表中取出每一个dev,用bus的match函数判断dev能否支持drv(通常通过结构体中的名称比较,但也有例外),若可以支持,调用drv的probe函数。②、在xxx_dev.c中xxx_init被执行,进而执行platform_device_register>>platform_device_add>>device_add,把device放入bus的dev链表,从bus的drv链表中取出每一个drv,用bus的match函数判断drv能否支持dev(通常通过结构体中的名称比较,但也有例外),若可以支持,调用dev的probe函数。
5、如何读?
app : read
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
……………
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN;//无数据并且是非阻塞方式打开,则立即返回
wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);//否则休眠
应用程序运行时无数据并且是非阻塞方式打开,线程就会进入休眠,谁来唤醒?由事件来唤醒:
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
wake_up_interruptible(&evdev->wait);
那么evdev_event又被谁调用?
以GPIO按键驱动程序为例说明:在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数
linux-2.6.22.6\drivers\input\keyboard\gpio_keys.c:
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
input_event(input, type, button->code, !!state);//上报事件
struct input_handle *handle;
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open) handle->handler->event(handle, type, code, value);
input_sync(input);
相关文章推荐
- ScrollView嵌套ListView冲突问题的最优解决方案
- elasticsearch es分布式集群初探
- JAVA并发编程学习笔记之AQS源码分析(共享与互斥)
- 排序算法个人总结(4)
- 在使用cppunit,搭建测试环境时遇到的问题以及解决办法(仅供参考)
- iOS开发笔记--Core Bluetooth开发
- elasticsearch java客户端 - 原生esClient
- Geekban极客班 第二周
- office2016 下载和激活
- elasticsearch java客户端 - Jest
- mysqldump常用命令总结
- lein auto reload 异常
- Spring(三)——核心容器Bean
- 求斐波那契数列的前10项,并逆序输出,用数组实现
- JAVA并发编程学习笔记之AQS源码分析(超时、中断与其他)
- 第十三周阅读程序 虚析构函数
- 博客迁移
- 学生管理系统(三层架构)
- PHP书写格式
- MyBatis review(一)——常见配置及方法