input子系统分享

个人input子系统的学习历程 学习所得:通过input子系统的学习,把按键、定时器、设备树又进行了一次复习,又有了不一样的理解,代码中我有加粗的部分,供大家参考。具体代码如下: 设备树部分...

个人input子系统的学习历程

学习所得:通过input子系统的学习,把按键、定时器、设备树又进行了一次复习,又有了不一样的理解,代码中我有加粗的部分,供大家参考。具体代码如下:

设备树部分如下:

mytest_key {
compatible = "mykey_gpio";
pinctrl-names = "default";
pinctrl-0 = <&myGPIO_key0
&myGPIO_key1>;
gpios = <&gpio5 1 GPIO_ACTIVE_LOW
&gpio4 14 GPIO_ACTIVE_LOW>;
};



驱动部分:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define KEYINPUT_NAME "keyinput" /* 名字 */
#define KEY0VALUE 0X01 /* KEY0按键值 */
#define INVAKEY 0XFF /* 无效的按键值 */
#define KEY_NUM 2 /* 按键数量 */


struct irq_keydesc{
unsigned char value; /*键值*/
int gpio;
int flags;
struct gpio_desc *gpio_key;
int irqnum; /* 中断号 */
irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
};



struct input_key_test{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
struct device_node *nd; /* 设备节点 */
struct irq_keydesc *irqkeydesc; /* 按键描述数组 */
struct timer_list timer; /* 定义一个定时器*/
unsigned char curkeynum; /* 当前的按键号 */
struct input_dev *inputdev; /* input结构体 */
};
static struct input_key_test keyinputdev;

static irqreturn_t key_handle0(int irq, void *dev_id)
{
struct input_key_test *dev = (struct input_key_test *)dev_id;
// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

dev->timer.data = (unsigned long)dev_id;
dev->curkeynum =0;
mod_timer(&dev->timer , jiffies + HZ/5); /*延时去抖*/
return IRQ_HANDLED;
}
static irqreturn_t key_handle1(int irq, void *dev_id)
{
struct input_key_test *dev = (struct input_key_test *)dev_id;
// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

dev->timer.data = (unsigned long)dev_id;
dev->curkeynum =1;
mod_timer(&dev->timer , jiffies + HZ/5); /*延时去抖*/
return IRQ_HANDLED;
}
static void timer_handle0(unsigned long arg)
{
int num;
int key;
struct input_key_test *dev = (struct input_key_test *)arg;
struct irq_keydesc *keydesc;
// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
// printk("key num = %d\n",dev->curkeynum);
num = dev->curkeynum;
keydesc = &dev->irqkeydesc[num];
key = gpiod_get_value(keydesc->gpio_key );
// printk("key is %d\n",key);
if(key == 0){ /* 按下按键 */
/* 上报按键值 */
//input_event(dev->inputdev, EV_KEY, keydesc->value, 1);
input_report_key(dev->inputdev, keydesc->value, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
input_sync(dev->inputdev);
} else { /* 按键松开 */
//input_event(dev->inputdev, EV_KEY, keydesc->value, 0);
input_report_key(dev->inputdev, keydesc->value, 0);
input_sync(dev->inputdev);
}
}

static int keyio_init(void)
{
int i;
int err;
int count;
enum of_gpio_flags flag;
/*获取设备树信息*/
keyinputdev.nd = of_find_node_by_path("/mytest_key"); /*获取设备节点*/
if(keyinputdev.nd == NULL)
{
printk("key node not find!\r\n");
return -1;
}
printk("keyinputdev.nd name is %s\n",keyinputdev.nd->name);
count = of_gpio_count(keyinputdev.nd);//此处注意点:of_gpio_count在匹配设备树时,是匹配的gpios ,由于前期用的是gpiod_get这个函数,对应的设备树中需要写成“key-gpios”,所以我在这个地方被自己给坑了很久
//另外在写驱动的时候,对函数的返回值最好做判断,就比如对count我之前没有做判断(设备树中还是key-gpios),导致count的返回值是 -2,而我又没有对count的返回判断(即,没有下面的if(count<0)这个判断),加载模块就挂掉,内核反馈的错误
//代码也看不懂,只能重启,修改代码,测试,挂掉,重启......循环下去

if(count < 0)
{
printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
/*
内存分配
请求大小:gpio个数 * 一个结构体的大小
返回:申请内存的指针,正好给结构体指针
*/
keyinputdev.irqkeydesc = kmalloc(count * sizeof(struct irq_keydesc), GFP_KERNEL);

keyinputdev.irqkeydesc[0].handler = key_handle0;
keyinputdev.irqkeydesc[1].handler = key_handle1;
for(i=0 ;i<count;i++)
{
keyinputdev.irqkeydesc[i].gpio = of_get_gpio_flags(keyinputdev.nd, i, &flag); /*获取gpio*/
keyinputdev.irqkeydesc[i].gpio_key = gpio_to_desc(keyinputdev.irqkeydesc[i].gpio); /*由gpio转换为gpio_desc*/
keyinputdev.irqkeydesc[i].flags = flag & OF_GPIO_ACTIVE_LOW;
keyinputdev.irqkeydesc[i].irqnum = gpio_to_irq(keyinputdev.irqkeydesc[i].gpio);
//keyinputdev.irqkeydesc[i].handler = key_handle0;
/*注册中断*/
err = request_irq(keyinputdev.irqkeydesc[i].irqnum, keyinputdev.irqkeydesc[i].handler,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq_test0", &keyinputdev);
if(err < 0)
{
printk("irq %d request failed!\r\n", keyinputdev.irqkeydesc[i].irqnum);
return -EFAULT;
}




}
keyinputdev.irqkeydesc[0].value =KEY_0;
keyinputdev.irqkeydesc[1].value =KEY_1;

/*设置定时器*/

setup_timer(&keyinputdev.timer , timer_handle0, (unsigned long)&keyinputdev);
keyinputdev.timer.expires = ~0 ;
add_timer(&keyinputdev.timer);
#if 0

init_timer(&keyinputdev.timer); //初始化定时器
keyinputdev.timer.function = timer_handle0; //设置定时器触发时函数
keyinputdev.timer.expires = ~0 ;
// add_timer(&keyinputdev.timer);
#endif

/* 申请input_dev */
keyinputdev.inputdev = input_allocate_device();

keyinputdev.inputdev->name = KEYINPUT_NAME;
keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY);
for(i=0 ;i<count;i++)
{
input_set_capability(keyinputdev.inputdev, EV_KEY, keyinputdev.irqkeydesc[i].value); /*设置keybit*/
}


/*注册input_dev*/
err = input_register_device(keyinputdev.inputdev);
return 0;

}

static int __init keyinput_init(void)
{
keyio_init();
return 0;
}

/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit keyinput_exit(void)
{
int count;
unsigned int i = 0;
printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
/*获取设备树信息*/
keyinputdev.nd = of_find_node_by_path("/mytest_key"); /*获取设备节点*/
count = of_gpio_count(keyinputdev.nd);

if(count < 0)
{
printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);

}
/* 删除定时器 */
#if 0
for(i=0 ;i<count;i++)
{
del_timer(&keyinputdev.irqkeydesc[i].timer ); /* 删除定时器 */
}
#endif
del_timer(&keyinputdev.timer ); /* 删除定时器 */
/* 释放中断 */
for (i = 0; i < count; i++) {
free_irq(keyinputdev.irqkeydesc[i].irqnum, &keyinputdev);
}
/* 释放input_dev */
input_unregister_device(keyinputdev.inputdev);
input_free_device(keyinputdev.inputdev);
}

module_init(keyinput_init);
module_exit(keyinput_exit);
MODULE_LICENSE("GPL");





  • 发表于 2020-11-06 14:00
  • 阅读 ( 385 )
  • 分类:经验分享

你可能感兴趣的文章

相关问题

0 条评论&回复

请先 登录 后评论
刘先生
刘先生

2 篇文章

作家榜 »

  1. 百问网-周老师 18 文章
  2. st_ashang 14 文章
  3. 渐进 12 文章
  4. zxq 11 文章
  5. helloworld 8 文章
  6. 星星之火 6 文章
  7. 谢工 5 文章
  8. Litchi_Zheng 5 文章