1. input device的注册是怎么样的,调用了哪些公用的函数
首先使用了late_initcall宏定义对驱动模型进行加载,在gpio_keys_init()函数中,使用了平台驱动注册函数platform_driver_register()来进行注册,其中参数结构体
static struct platform_driver gpio_keys_device_driver= {
.probe =gpio_keys_probe,
.remove = gpio_keys_remove,
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
.pm = &gpio_keys_pm_ops,
.of_match_table =of_match_ptr(gpio_keys_of_match),
}
};
在注册过程中调用了gpio_keys_probe()函数完成了input device的注册。在gpio_keys_probe()函数中主要完成了以下事情:
a) 定义结构体 struct input_dev *input,并使用 input =input_allocate_device(input)将input申请为输入设备。
b) 配置input信息
input->name =pdata->name ? :pdev->name;
input->phys="gpio-keys/input0";
input->dev.parent=&pdev->dev;
input->open=gpio_keys_open;
input->close =gpio_keys_close;
input->id.bustype =BUS_HOST;
input->id.vendor =0x0001;
input->id.product=0x0001;
input->id.version=0x0100;
c) 通过error =input_register_device(input)函数向kernel注册一个输入设备。
此外,gpio_keys_probe()中还调用了gpio_keys_setup_key()函数对gpio进行配置。
2. GPIO的申请,初始化,以及如何控制,中断服务的注册,中断如何处理的。
在gpio_keys_setup_key()函数中,先使用gpio_is_valid来测试端口是否合法,然后使用gpio_request_one进行GPIO的申请,同时将引脚配置成输入,通过irq =gpio_to_irq(button_irq)将引脚设为外部中断,同时获得的中断号赋值给bdata_irq,然后设置外部中断服务函数isr = gpio_keys_gpio_isr以及配置中断处理标志irqflag为上升沿触发和下降沿触发,。最后通过 error =request_any_context_irq(bdata->irq, isr, irqflags,desc, bdata)来完成中断服务的注册。在对input进行配置时,由input->open =gpio_keys_open; 、input->close=gpio_keys_close可知通过gpio_keys_open/gpio_keys_close
函数可以对GPIO端口进行打开和关闭,对GPIO端口进行控制。
该程序中具体的中断流程如下:
1. 首先完成中断的配置以及注册
2. 按键按下时,触发外部中断,调用中断服务程序gpio_keys_gpio_isr,使用定时器进行消抖,然后调用工作队列中的gpio_keys_work_func()函数
3. 通过gpio_keys_gpio_report_events()函数中的gpio_get_value_cansleep(button_gpio)函数来对按键进行扫描,获得按键值,使用input_event传递事件信息,最后使用input_sync()完成事件的同步。
最后使用intgpio_keys_remove()中完成卸载,该函数主要是删除定时器,取消工作队列的工作,释放申请的引脚, 通过input_unregister_device(input)注销输入设备, 最后通过kfree(ddata)释放之前申请的数据内存空间。
Matrix_keypad.c驱动程序首先使用了module_platform_driver(matrix_keypad_driver)
进行平台驱动注册和注销函数,先看平台驱动注册函数的参数结构体:
static struct platform_drivergpio_keys_device_driver = {
.probe =gpio_keys_probe,
.remove = gpio_keys_remove,
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
.pm = &gpio_keys_pm_ops,
.of_match_table =of_match_ptr(gpio_keys_of_match),
}
};
在注册的时候就会去执行gpio_keys_probe函数,在注销的时候就会执行gpio_keys_remove的函数,然后gpio_keys_pm_ops,这个由宏static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops,gpio_keys_suspend,gpio_keys_resume)最终会调用gpio_keys_remove和gpio_keys_suspend函数控制电源的进入工作状态或者低功耗状态。
gpio_keys_probe()分析:
在gpio_keys_probe()函数中主要完成了以下任务:
a) 为键盘分配内存空间,定义结构体 struct input_dev *input,并使用 input =input_allocate_device(input)将input申请为输入设备。
b) 对keypad和input进行配置
c) 调用matrix_keypad_init_gpio()函数完成对GPIO端口的初始化。
d) 使用input_register_device对设备进行注册。
GPIO设置Matrix_keypad_init_gpio()分析
在该函数中,对GPIO端口进行初始化,由三列GPIO和两行GPIO端口构成有6个按键的矩阵键盘,先对三列GPIO进行request申请,并使用gpio_dorection_output将三列GPIO端口配置成输出端,输出为高电平。然后对两行GPIO进行request申请,并使用gpio_dorection_input配置成输入端口。并使用request_irq(gpoi_to_irq(pdata.row_gpio[i])将两行GPIO端口设置为外部中断,并向内核完成中断的注册。
中断流程分析:
当按键按下时,按键触发中断进入中断服务程序matrix_keypad_interrupt()函数中,该函数主要完成了INIT_DELAYED_WORK工作队列中按键扫描matrix_keypad_scan()任务。
Matrix_keypad_scan()分析:
先使用for()循环对每一列GPIO端口进行选择,使用activate_col()函数将每一列GPIO配置成输出端,且输出为高电平,然后嵌套for循环对已经配置成输入的两行GPIO进行逐个分析,当有按键按下时,由row_asserted(pdata,row)?(1<