fmql之Linux Input子系统
正点原子第43章。
input子系统
驱动程序
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : keyinput.c
作者 : Skylar
版本 : V1.0
描述 : Input子系统
其他 : key
论坛 : www.openedv.com
日志 : 初版V1.0 2024/10/9 创建
***************************************************************/
#include <linux/module.h>
#include <linux/of_gpio.h>
// #include <linux/cdev.h>
// #include <linux/uaccess.h>
#include <linux/platform_device.h>
// #include <linux/leds.h>
// #include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/input-event-codes.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/kern_levels.h>
#define PS_KEY_CODEKEY_0
struct mykey_dev {
struct input_dev *idev;// input_dev指针
struct timer_list timer;// 消抖
int gpio;
int irq;
};
/*
* @description : 定时器服务函数,用于按键消抖,定时时间到了以后
* 再读取按键值,根据按键的状态上报相应的事件
* @param – arg : arg 参数可以在初始化定时器的时候进行配置
* @return : 无
*/
static void key_timer_function(struct timer_list *arg)
{
int val = 0;
struct mykey_dev *key = from_timer(key, arg, timer);
val = gpio_get_value(key->gpio);
input_report_key(key->idev, PS_KEY_CODE, !val);// 上报按键事件
input_sync(key->idev);// 同步事件
enable_irq(key->irq);// 使能按键中断
}
/*
* @description : 按键中断服务函数
* @param – irq : 触发该中断事件对应的中断号
* @param – arg : arg 参数可以在申请中断的时候进行配置
* @return : 中断执行结果
*/
static irqreturn_t mykey_interrupt(int irq, void *arg)
{
struct mykey_dev *key = (struct mykey_dev *)arg;
/* 判断触发中断的中断号是否是按键对应的中断号 */
if(key->irq != irq)
return IRQ_NONE;
/* 按键防抖处理,开启定时器延时 15ms */
disable_irq_nosync(irq);// 禁止按键中断
mod_timer(&key->timer, jiffies + msecs_to_jiffies(15));
return IRQ_HANDLED;
}
/*
* @description : 按键初始化函数
* @param – pdev : platform 设备指针
* @return : 成功返回 0,失败返回负数
*/
static int mykey_init(struct platform_device *pdev)
{
struct mykey_dev *key = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
unsigned long irq_flags=0;
int ret;
key->gpio = of_get_named_gpio(dev->of_node, "key-gpio", 0);
if(!gpio_is_valid(key->gpio)){
dev_err(dev, "Failed to get gpio");
return -EINVAL;
}
ret = devm_gpio_request(dev, key->gpio, "Key Gpio");
if(ret){
dev_err(dev, "Failde to request gpio");
return ret;
}
gpio_direction_input(key->gpio);
/* 获取 GPIO 对应的中断号 */
// key->irq = irq_of_parse_and_map(dev->of_node, 0);
key->irq=gpio_to_irq(key->gpio);
if (!key->irq)
return -EINVAL;
/* 获取设备树中指定的中断触发类型 */
irq_flags = irq_get_trigger_type(key->irq);
if (IRQF_TRIGGER_NONE == irq_flags)
irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
/* 申请中断 */
return devm_request_irq(dev, key->irq, mykey_interrupt,
irq_flags, "PS_Key0 IRQ", key);
}
/*
* @description : platform 驱动的 probe 函数,当驱动与设备
* 匹配成功以后此函数会被执行
* @param – pdev : platform 设备指针
* @return : 0,成功;其他负值,失败
*/
static int mykey_probe(struct platform_device *pdev)
{
struct mykey_dev *key;
struct input_dev *idev;
int ret;
dev_info(&pdev->dev, "Key driver and device have been matched\n");
/* 为key指针分配内存 */
key = devm_kzalloc(&pdev->dev, sizeof(struct mykey_dev), GFP_KERNEL);
if(!key)
return -ENOMEM;
platform_set_drvdata(pdev, key);
/* 初始化key */
ret = mykep_init(pdev);
if(ret){
return ret;
}
/* 定时器初始化 */
timer_setup(&key->timer, key_timer_function, 0);
/* input_dev 初始化 */
idev = devm_input_allocate_device(&pdev->dev);
if(!idev)
return -ENOMEM;
key->idev = idev;
idev->name = "mykey";
__set_bit(EV_KEY, idev->evbit); // 可产生按键事件
__set_bit(EV_REP, idev->evbit); // 可产生重复事件
__set_bit(PS_KEY_CODE, idev->keybit); // 可产生 KEY_0 按键事件
/* 注册key input设备 */
return input_register_devive(idev);
}
/*
* @description : platform 驱动的 remove 函数,当 platform 驱动模块
* 卸载时此函数会被执行
* @param – dev : platform 设备指针
* @return : 0,成功;其他负值,失败
*/
static int mykey_remove(struct platform_device *pdev)
{
struct mykey_dev *key = platform_get_drvdata(pdev);
/* 删除定时器 */
del_timer_sync(&key->timer);
/* 注销key设备驱动 */
input_unregister_device(key->idev);
dev_info(&pdev->dev, "Key device was removed\n");
return 0;
}
/* 匹配列表 */
static const struct of_device_id key_of_match[] = {
{.compatible = "fmql,key"},
{/* Sentinel */}
};
static struct platform_driver mykey_driver = {
.driver = {
.name= "mykey",/* platform_driver name*/
.of_match_table= key_of_match,
},
.probe = mykey_probe,
.remove = mykey_remove,
};
module_platform_driver(mykey_driver);
MODULE_AUTHOR("Skylar <Skylar@33.com>");
MODULE_DESCRIPTION("Key Driver, Input Subsystem");
MODULE_LICENSE("GPL");
测试程序
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : keyinputAPP.c
作者 : Skylar
版本 : V1.0
描述 : key Input_Subsystem
其他 :
使用方法 : ./keyinputApp /dev/input/eventX
论坛 : www.openedv.com
日志 : 初版V1.0 2024/10/9 创建
***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
// #include <sys/ioctl.h>
// #include <signal.h>
#include <linux/input.h>
/*
* @description : main 主程序
* @param – argc : argv 数组元素个数
* @param – argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[]
{
int fd, ret;
struct input_event ev;
if(argc != 2){
printf("Usage:\n"
"\t./keyinputApp /dev/input/eventX @ Open Key\n"
);
return -1;
}
fd = open(argv[1], O_RDWR);
if(fd < 0){
printf("Erroe: file %s open failed\r\n", argv[1]);
return -1;
}
/* 读取按键数据 */
for ( ; ; ){
ret = read(fd, &ev, sizeof(struct input_event));
if(ret){
switch(ev.type){
case EV_KEY: // 按键事件
if(KEY_0 == ev.code){ // 判断是不是 KEY_0 按键
if(ev.value) // 按键按下
printf("PS Key0 Press\n");
else
printf("PS Key0 Release\n");
}
break;
/* 其他类型的事件,自行处理 */
case EV_REL:
break;
case EV_ABS:
break;
case EV_MSC:
break;
case EV_SW:
break;
}
} else {
printf("Error: file %s read failed!\r\n", argv[1]);
goto out;
}
}
out:
close(fd);
return 0;
})
运行
Linux自带按键驱动
dts中要写成compatible = “gpio-keys”
修改dts
原文地址:https://blog.csdn.net/qq_41656020/article/details/142786074
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!