ZYNQ7020 linux下input 子系统框架来处理输入事件

 #include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/timer.h>
 #include <linux/of_irq.h>
 #include <linux/interrupt.h>
 #include <linux/input-event-codes.h>
 
 #define PS_KEY0_CODE		KEY_0
 
 /* 自定义的按键设备结构体 */
 struct mykey_dev {
     struct input_dev *idev;	// 按键对应的input_dev指针
     struct timer_list timer;	// 消抖定时器
     int gpio;					// 按键对应的gpio编号
     int irq;					// 按键对应的中断号
 };
 
 
 //定时器服务函数,用于按键消抖,定时时间到了以后再读取按键值,根据按键的状态上报相应的事件
 //arg参数可以在初始化定时器的时候进行配置
 static void key_timer_function(struct timer_list* arg)
 {
     int val=0;
	 
	 //获取包含定时器结构体的首地址(这里指的是struct mykey_dev的地址,这样你才能知道是那个gpio产生的事件
	 //若你不获取struct mykey_dev地址,最后上报input事件的时候会出现系统异常)
	 struct mykey_dev *key = from_timer(key,arg,timer);  
 
     /* 读取按键值并上报按键事件 */
     val = gpio_get_value(key->gpio);
     input_report_key(key->idev,PS_KEY0_CODE, !val);	// 上报按键事件
     input_sync(key->idev);								// 同步事件

     /* 使能按键中断 */
     enable_irq(key->irq);
 }
 

 //按键中断服务函数
 //参数1:触发该中断事件对应的中断号
 //参数2:arg参数可以在申请中断的时候进行配置
 //返回值:中断执行结果
 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);			// 禁止按键中断 ????????????
	 //内核定时器并不是周期运行的,超时后就会自动关闭,因此如果需要周期性使用,
	 //需要在定时处理函数中重新开启
	 //重启定时器,修改定时值,该函数会激活定时器
	 //参数1:需要修改的定时器
	 //参数2:修改定时的时间
	 //jiffies/HZ为系统运行时间(秒)
	 //msecs_to_jiffies() 将ms/us/ns转换为jiffies类型
	 //注:在mykey_probe函数中初始化定时器 timer_setup
     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=0;
 
    /* 从设备树中获取GPIO */
    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;
    }
    
    /* 申请使用GPIO */
    ret = devm_gpio_request(dev, key->gpio, "Key Gpio");
    if (ret) {
        dev_err(dev, "Failed to request gpio");
        return ret;
    }
 
    /* 将GPIO设置为输入模式 */
    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=0;
	
	 //启动过程、或者模块加载过程等通知类的信息等,一般只通知一次
	 //参数1:设备的详细信息
     dev_info(&pdev->dev, "Key device and driver matched successfully!\n");
	
    /* 为key指针分配内存 */
	//和设备有关的函数,当设备被卸载时,分配的内存会被自动释放
	//参数1:内存空间和绑定的dev,卸载时,内存空间正常释放
	//GFP_KERNEL:内核空间中正常的内存分配
	//返回值:申请成功返回内存指针,失败返回NULL
    key = devm_kzalloc(&pdev->dev, sizeof(struct mykey_dev), GFP_KERNEL);
    if (!key)
        return -ENOMEM;
   
	//用于将key指针存放到pdev->dev.中去
    platform_set_drvdata(pdev, key);
 
    //* 初始化按键 */
    ret = mykey_init(pdev);
    if (ret)
        return ret;
 
    /* 定时器初始化 */
    timer_setup(&key->timer,key_timer_function,0);
	
    /* input_dev初始化 */
	//先申请一个input_dev结构体变量,该函数申请的变量在设备卸载时会自动释放
    idev = devm_input_allocate_device(&pdev->dev);
    if (!idev)
        return -ENOMEM;
 
    key->idev = idev;
    idev->name = "mykey";	//设置input_dev名字
 
    __set_bit(EV_KEY, idev->evbit);				// 可产生按键事件
    __set_bit(EV_REP, idev->evbit);				// 可产生重复事件
	__set_bit(PS_KEY0_CODE, idev->keybit);		// 可产生KEY_0按键事件
 
    /* 注册按键输入设备 */
     return input_register_device(idev);
 }
 
 /*
  * @description			: platform驱动的remove函数,当platform驱动模块
  * 						 卸载时此函数会被执行
  * @param – dev			: platform设备指针
  * @return				: 0,成功;其他负值,失败
  */
 static int mykey_remove(struct platform_device *pdev)
 {
	 //用于将pdev指针存放到key中去
     struct mykey_dev *key = platform_get_drvdata(pdev);
 
     //删除定时器:该函数会等待其他处理器使用完定时器再删除,
	 //该函数不能再中断上下文中使用,区别与del_timer
     del_timer_sync(&key->timer);
 
     /* 卸载按键设备 */
     input_unregister_device(key->idev);
 
     return 0;
 }
 
 /* 匹配列表 */
 static const struct of_device_id key_of_match[] = {
     { .compatible = "alientek,key" },
     { /* Sentinel */ }	//最后一个元素一定要为空
 };
 
 /* platform驱动结构体 */
 static struct platform_driver mykey_driver = {
     .driver = {
         .name			= "zynq-key",		// 驱动名字,用于和设备匹配
         .of_match_table	= key_of_match,	// 设备树匹配表,用于和设备树中定义的设备匹配
     },
     .probe          = mykey_probe,	// probe函数
     .remove         = mykey_remove,	// remove函数
 };
 
 module_platform_driver(mykey_driver);
 
 MODULE_AUTHOR("lnb");
 MODULE_DESCRIPTION("input");
 MODULE_LICENSE("GPL");

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值