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
    评论
Zynq-7000系列是Xilinx公司的一款嵌入式SoC(System-on-Chip)产品,它集成了CPU、可编程逻辑(PL)和片上存储器在一个芯片上。移植LinuxZynq-7020主要是为了提供一个基于Linux的操作系统环境,使得开发者能够利用其强大的处理能力并运行各种软件应用。 移植步骤一般包括以下几个关键环节: 1. **硬件配置**:首先,确认Zynq-7020的设备树(Device Tree)配置正确,因为Linux内核依赖于这些信息来识别硬件资源。 2. **下载工具链**:安装适合Zynq的交叉编译工具链,以便在主机系统上构建Linux内核和应用程序。 3. **编译内核**:从源码开始编译Linux内核,配置选项通常会包含对Zynq处理器的支持,如ARM Cortex-A9 CPU和PL部分。 4. **创建启动加载器**:为Zynq定制启动加载器(如u-boot或U-Boot Lite),以便引导Linux内核进入PL。 5. **PL上的初始化**:编写引导代码,使PL初始化完成后将控制权交给CPU,然后加载Linux内核。 6. **内核配置**:可能需要对内核进行额外配置,以支持PL上的硬件加速功能(如DMA控制器、USB等)。 7. **分区管理**:设置存储设备(如SD卡、Nor Flash)的分区,以及挂载点,用于存放Linux文件系统。 8. **根文件系统**:构建适合Zynq的根文件系统,可能需要自定义或使用第三方预构建的像Yocto Project这样的项目。 9. **测试和调试**:最后,进行系统级别的测试以确保Linux能在Zynq-7020上正常运行,可能会涉及到硬件驱动的验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值